iPhone (iOS): copying files from main bundle to documents folder causes crash

。_饼干妹妹 提交于 2019-12-17 19:12:38

问题


I am trying to set up my application so that on first launch, a series of files located in the "Populator" folder in the main bundle are copied into the documents directory.

My current implementation is as follows:

- (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;
}

However this crashes the first time it is run with the following console messages (but the files are copied over). The next time the app is opened, it does not crash.

    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
)

Does anyone have any suggestions as to what is going wrong? I already have some code set up to implement the "only on first launch" functionality, but have not included it here for clarity.

Thanks


回答1:


I don't know a lot about iPhone programming or objective C, but out of curiosity, what is error in that case if the copy operation actually succeeded? Could it be the log lines that are crashing if there was no error?

[edit] Also, are you allowed to copy the entire contents of a subdirectory like that? (Again, I'm unfamiliar with the iOS API, just identifying possible sources of error based on what I know of other languages/APIs)




回答2:


   NSError *error;

You are declaring a local variable without initializing it. Therefore, it will be filled with garbage.

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

If no error occurs on this line, the garbage status of error would still remain.

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

Now you send a message to some random, uninitialized location. This is the source of the crash.


To avoid this, initialize error to nil.

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

Or print the error only when -copyItemAtPath:… returns NO (in which the error is correctly populated).

if (![[NSFileManager defaultManager] copyItemAtPath:sourcePath ...]) {
  NSLog(...); 
}



回答3:


I just read through my code and found the issue. As Sean Edwards points out above, there is no error if it succeeds - hence the crash.

Here is my new code for those interested:

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:


you should check whether the file already exists! Then copy.

+ (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 are localize strings of the application.




回答5:


You log an error before you know that there is an error

put the code in an if-block

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

To describe your problem in more detail: the pointer of error points ANYWHERE and that object does not recognize that message. Therefore you get an exception




回答6:


As a general programming practice, it's always best to initialize your variables with a default value:

NSError *error = nil;

In Objective-C, it is valid to send a message to nil. So, in your case, error variable would not cause a crash if it was initialized to nil.

For more info on the subject check Sending Messages to nil section at https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html



来源:https://stackoverflow.com/questions/3238143/iphone-ios-copying-files-from-main-bundle-to-documents-folder-causes-crash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!