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

发布于 2024-09-09 11:00:16 字数 2287 浏览 5 评论 0原文

我正在尝试设置我的应用程序,以便在首次启动时,位于主包中“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
)

有人对出了什么问题有什么建议吗?我已经设置了一些代码来实现“仅在首次启动时”功能,但为了清楚起见,没有将其包含在此处。

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

江心雾 2024-09-16 11:00:16
   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(...); 
}
   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(...); 
}
风流物 2024-09-16 11:00:16

我刚刚阅读了我的代码并发现了问题。正如肖恩·爱德华兹(Sean Edwards)上面指出的那样,如果成功,就不会出现错误 - 因此会发生崩溃。

这是我的新代码,供感兴趣的人参考:

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]);
}

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]);
}
手长情犹 2024-09-16 11:00:16

我对 iPhone 编程或 Objective C 不太了解,但出于好奇,如果复制操作确实成功,那么在这种情况下错误是什么?如果没有错误,是否可能是日志行崩溃了?

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

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)

时光与爱终年不遇 2024-09-16 11:00:16

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

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

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.

逐鹿 2024-09-16 11:00:16

在您知道存在错误之前记录错误,

将代码放入 if 块中

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

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

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

锦上情书 2024-09-16 11:00:16

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

NSError *error = nil;

在 Objective-C 中,向 nil 发送消息是有效的。因此,在您的情况下,如果错误变量初始化为nil,则不会导致崩溃。

有关该主题的更多信息,请查看 https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文