代码之家  ›  专栏  ›  技术社区  ›  Jack

iPhone(iOS):将文件从主包复制到文档文件夹会导致崩溃

  •  15
  • Jack  · 技术社区  · 15 年前

    我正在尝试设置我的应用程序,以便在第一次启动时,将位于主包中“populator”文件夹中的一系列文件复制到documents目录中。

    我目前的实施情况如下:

    - (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 回复  |  直到 13 年前
        1
  •  4
  •   Sean Edwards    15 年前

    我对iPhone编程或目标C不太了解,但出于好奇,如果复制操作真的成功了,那么在这种情况下会出现什么错误?如果没有错误,是日志行崩溃了吗?

    [编辑]另外,是否允许复制这样的子目录的全部内容?(同样,我不熟悉iOS API,只是根据我对其他语言/API的了解来识别可能的错误源)

        2
  •  15
  •   kennytm    15 年前
       NSError *error;
    

    声明局部变量而不初始化它。因此,它将充满垃圾。

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

    如果此行没有出现错误,则 error 还是会留下来。

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

    现在,您向一些随机的、未初始化的位置发送消息。这就是车祸的原因。


    要避免这种情况,请初始化 错误 nil .

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

    或者只在以下情况下打印错误 -copyItemAtPath:… 返回no(其中 错误 正确填充)。

    if (![[NSFileManager defaultManager] copyItemAtPath:sourcePath ...]) {
      NSLog(...); 
    }
    
        3
  •  5
  •   Jack    15 年前

    我刚看完我的代码,发现了问题。正如肖恩·爱德华兹在上面指出的,如果它成功了,就不会有任何错误——这就是崩溃的原因。

    以下是我对感兴趣的人的新代码:

    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
  •  4
  •   Vaibhav Saran    13 年前

    您应该检查文件是否已经存在!然后复制。

    + (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 是应用程序的本地化字符串。

        5
  •  2
  •   Duck    14 年前

    在知道有错误之前记录一个错误

    将代码放入if块

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

    更详细地描述您的问题:错误指针指向任何地方,而该对象无法识别该消息。所以你会得到一个例外

        6
  •  1
  •   Ahmet Ardal    14 年前

    作为一般编程实践,最好用默认值初始化变量:

    NSError *error = nil;
    

    在Objective-C中,向 nil . 因此,在您的例子中,如果将错误变量初始化为 .

    有关主题的详细信息,请查看 Sending Messages to nil 截面 https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html