iPhone (iOS): копирование файлов из основного пакета в папку документов приводит к сбою - PullRequest
15 голосов
/ 13 июля 2010

Я пытаюсь настроить свое приложение таким образом, чтобы при первом запуске ряд файлов, расположенных в папке «Populator» в основном комплекте, копировался в каталог документов.

Моя текущая реализация выглядит следующим образом:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Populator"];
  NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:@"Files"];
  NSLog(@"Source Path: %@\n Documents Path: %@ \n Folder Path: %@", sourcePath, documentsDirectory, folderPath);

  NSError *error;

  [[NSFileManager defaultManager] copyItemAtPath:sourcePath 
                                        toPath:folderPath
                                         error:&error];

  NSLog(@"Error description-%@ \n", [error localizedDescription]);
  NSLog(@"Error reason-%@", [error localizedFailureReason]);
  ....
  return YES;
}

Однако происходит сбой при первом запуске со следующими консольными сообщениями (но файлы копируются). В следующий раз, когда приложение открывается, оно не падает.

    2010-07-13 15:14:26.418 AppName[5201:207] Source Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/AppName.app/Populator
 Documents Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents 
 Folder Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents/Files
2010-07-13 15:14:26.466 AppName[5201:207] *** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c
2010-07-13 15:14:26.475 AppName[5201:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c'
2010-07-13 15:14:26.495 AppName[5201:207] Stack: (
    40911435,
    2569270537,
    41183227,
    40645910,
    40642578,
    9142,
    2815466,
    2819475,
    2844680,
    2826401,
    2858055,
    49271164,
    40452156,
    40448072,
    2817668,
    2850273,
    8776,
    8630
)

У кого-нибудь есть предложения относительно того, что идет не так? У меня уже есть некоторый код, настроенный для реализации функциональности «только при первом запуске», но я не включил его здесь для ясности.

Спасибо

Ответы [ 6 ]

15 голосов
/ 13 июля 2010
   NSError *error;

Вы объявляете локальную переменную без ее инициализации. Поэтому он будет заполнен мусором.

  [[NSFileManager defaultManager] copyItemAtPath:sourcePath 
                                        toPath:folderPath
                                         error:&error];

Если в этой строке не возникнет ошибки, состояние мусора error все равно останется.

  NSLog(@"Error description-%@ \n", [error localizedDescription]);

Теперь вы отправляете сообщение в случайное неинициализированное местоположение. Это источник крушения.


Чтобы избежать этого, инициализируйте error в nil.

NSError* error = nil;
//             ^^^^^

Или выведите ошибку только тогда, когда -copyItemAtPath:… вернет NO (при этом error заполнен правильно).

if (![[NSFileManager defaultManager] copyItemAtPath:sourcePath ...]) {
  NSLog(...); 
}
5 голосов
/ 13 июля 2010

Я только что прочитал свой код и нашел проблему. Как указывает Шон Эдвардс выше, в случае успеха ошибки не возникает - отсюда и крах.

Вот мой новый код для интересующихся:

if([[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:folderPath error:&error]){
    NSLog(@"File successfully copied");
} else {
    NSLog(@"Error description-%@ \n", [error localizedDescription]);
    NSLog(@"Error reason-%@", [error localizedFailureReason]);
}
4 голосов
/ 02 апреля 2013

Вы должны проверить, существует ли файл уже! Затем скопируйте.

+ (BOOL) getFileExistence: (NSString *) filename
{
    BOOL IsFileExists = NO;

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDir = [documentPaths objectAtIndex:0];
    NSString *favsFilePath = [documentsDir stringByAppendingPathComponent:filename];

    NSFileManager *fileManager = [NSFileManager defaultManager];

    // Check if the database has already been created in the users filesystem
    if ([fileManager fileExistsAtPath:favsFilePath])
    {
        IsFileExists = YES;
    }
    return IsFileExists;
}

+ (NSString *)dataFilePath:(NSString *)filename {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDirectory = [paths objectAtIndex:0];
    return [docDirectory stringByAppendingPathComponent:filename];
}

- (void)copyFileToLocal:(NSString *)filename
{

    if (![AppDelegate getFileExistence:filename])
    {
        NSError *error;
        NSString *file = [[NSBundle mainBundle] pathForResource:filename ofType:nil];

        if (file)
        {
            if([[NSFileManager defaultManager] copyItemAtPath:file toPath:[AppDelegate dataFilePath:filename] error:&error]){
                NSLog(@"File successfully copied");
            } else {

                [[[UIAlertView alloc]initWithTitle:NSLocalizedString(@"error", nil) message: NSLocalizedString(@"failedcopydb", nil)  delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil)  otherButtonTitles:nil] show];
                NSLog(@"Error description-%@ \n", [error localizedDescription]);
                NSLog(@"Error reason-%@", [error localizedFailureReason]);
            }
            file = nil;
        }
    }
}

NSLocalizedString - локализованные строки приложения.

4 голосов
/ 13 июля 2010

Я не знаю много о программировании iPhone или цели C, но из любопытства, что является ошибкой в ​​том случае, если операция копирования действительно удалась? Могут ли происходить сбои строк журнала, если не было ошибок?

[править] Кроме того, вам разрешено копировать все содержимое такого подкаталога? (Опять же, я не знаком с API iOS, просто определяю возможные источники ошибок на основе того, что знаю о других языках / API)

2 голосов
/ 13 июля 2010

Вы регистрируете ошибку, прежде чем узнаете, что есть ошибка

поместите код в блок if

if(error)
{
 NSLog(@"Error description-%@ \n", [error localizedDescription]);
 NSLog(@"Error reason-%@", [error localizedFailureReason]);
}

Для более подробного описания вашей проблемы: указатель ошибкиуказывает где-нибудь, и этот объект не распознает это сообщение.Поэтому вы получаете исключение

1 голос
/ 07 июня 2012

В качестве общей практики программирования всегда лучше инициализировать переменные значением по умолчанию:

NSError *error = nil;

В Objective-C допустимо отправлять сообщение на nil.Таким образом, в вашем случае переменная ошибки не вызовет сбой, если она будет инициализирована в nil.

Для получения дополнительной информации о предмете проверки Sending Messages to nil раздел в https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html

...