创建到文档目录的路径会导致 NSInvalidArgumentException 和无法识别的选择器问题

Posted

技术标签:

【中文标题】创建到文档目录的路径会导致 NSInvalidArgumentException 和无法识别的选择器问题【英文标题】:Creating a path to the documentsDirectory results in a NSInvalidArgumentException and unrecognized selector issue 【发布时间】:2018-01-22 21:27:09 【问题描述】:

我正在学习 Obj-C,但我一生都无法弄清楚为什么会发生这种崩溃。这是错误消息:

2018-01-22 16:10:00.009334-0500 ParkSmartObjC[1997:189530] Finished picking media
2018-01-22 16:10:00.163798-0500 ParkSmartObjC[1997:189530] B4A78674-6164-44CE-8EED-153AA8C0BDA2
2018-01-22 16:10:00.164109-0500 ParkSmartObjC[1997:189530] -[__NSSingleObjectArrayI stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x60000020bd00
2018-01-22 16:10:00.167466-0500 ParkSmartObjC[1997:189530] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSSingleObjectArrayI stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x60000020bd00'
*** First throw call stack:
(
0   CoreFoundation                      0x0000000109d731cb __exceptionPreprocess + 171
1   libobjc.A.dylib                     0x000000010928ff41 objc_exception_throw + 48
2   CoreFoundation                      0x0000000109df3914 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3   CoreFoundation                      0x0000000109cf6178 ___forwarding___ + 1432
4   CoreFoundation                      0x0000000109cf5b58 _CF_forwarding_prep_0 + 120
5   ParkSmartObjC                       0x0000000107f4d9fa -[PhotoVC imagePickerController:didFinishPickingMediaWithInfo:] + 426
6   UIKit                               0x000000010a64507f -[UIImagePickerController _imagePickerDidCompleteWithInfo:] + 127
7   UIKit                               0x000000010a644999 __60-[UIImagePickerController didSelectMediaWithInfoDictionary:]_block_invoke + 42
8   libdispatch.dylib                   0x000000010c5193f7 _dispatch_call_block_and_release + 12
9   libdispatch.dylib                   0x000000010c51a43c _dispatch_client_callout + 8
10  libdispatch.dylib                   0x000000010c5256f0 _dispatch_main_queue_callback_4CF + 628
11  CoreFoundation                      0x0000000109d35ef9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
12  CoreFoundation                      0x0000000109cfa662 __CFRunLoopRun + 2402
13  CoreFoundation                      0x0000000109cf9a89 CFRunLoopRunSpecific + 409
14  GraphicsServices                    0x000000010eeaf9c6 GSEventRunModal + 62
15  UIKit                               0x000000010a1ee23c UIApplicationMain + 159
16  ParkSmartObjC                       0x0000000107f4ca9f main + 111
17  libdyld.dylib                       0x000000010c596d81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

这是崩溃的代码:

- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info 

if(info[UIImagePickerControllerOriginalImage]) 

    UIImage *image = info[UIImagePickerControllerOriginalImage];
    NSData *data = UIImageJPEGRepresentation(image, 0.6);
    NSString *uuid = [[NSUUID UUID] UUIDString];

    NSString *path = [ImageSaveHelper getDocumentsDirectory];
    NSLog(@"%@", uuid);
    //The UUID prints fine...
    NSString *filePath = [[NSString alloc] init];
   ->>> filePath = [path stringByAppendingPathComponent:uuid]; //SEEMS TO CRASH HERE. WHAT HAVE I DONE WRONG?
    [data writeToFile:filePath atomically:YES];

    //Save photo to current CarLocation object
    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm beginWriteTransaction];
    self.carLoc.photoUID = uuid;
    self.carLoc.isPhotoTaken = YES;
    [realm commitWriteTransaction];

    self.carImage.image = image;
    [picker dismissViewControllerAnimated:YES completion:nil];


我正在尝试从 ImagePickerController 中选择一个图像,然后将数据保存到具有 UUID 的磁盘上的某个位置。当我尝试将 UUID 附加到 filePath 时,它似乎崩溃了。我从辅助函数中获取 filePath。我做错了什么?

编辑:这里是辅助函数...

+ (NSString*) getDocumentsDirectory 
NSArray *paths = [NSArray arrayWithObjects:NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES), nil];
NSString *filePath = [paths objectAtIndex:0];
return filePath;


【问题讨论】:

[ImageSaveHelper getDocumentsDirectory] 返回什么? NSString*,对不起 看起来像一个 __NSSingleObjectArrayI 数组,其中一个对象不是 'NSString` ;) 确实如此。我不知道为什么。它完全按照回答的人建议做的事情。 用你的标题来解释问题……而不是解释你的痛苦。在 SO 上提出问题时,我们都会经历痛苦 【参考方案1】:

阅读错误信息:

[__NSSingleObjectArrayI stringByAppendingPathComponent:]:无法识别的选择器

明确指出方法getDocumentsDirectory 返回一个数组,而不是单个字符串。所以你必须得到数组的第一个对象:

NSArray *pathArray = [ImageSaveHelper getDocumentsDirectory];
NSString *path = pathArray[0];
NSString *filePath = [path stringByAppendingPathComponent:uuid];

编辑:

您的辅助方法返回一个数组,因为您正在使用 NSSearchPathForDirectoriesInDomains 的结果初始化一个数组,而 NSSearchPathForDirectoriesInDomains 已经是一个数组。结果是一个嵌套数组

@[@[@"path", @"path", @"path"]];

并且在索引 0 处获取对象仍然是一个数组。


解决方法是将getDocumentsDirectory改为

+ (NSString*) getDocumentsDirectory 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    return paths[0];

那么你可以保留语法

NSString *path = [ImageSaveHelper getDocumentsDirectory];
NSString *filePath = [path stringByAppendingPathComponent:uuid];

PS:我建议学习 Swift 而不是 ObjC。 Swift 编译器不会让你做那些类型不匹配的烂摊子?

【讨论】:

你好。谢谢你的想法。我已经编辑了我的帖子以包含显然返回数组的方法。我无法将该方法的结果初始化为一个数组,因为它显式地返回一个 NSString。你能看看这个函数并告诉我这怎么可能吗?我完全按照您的拼写进行了尝试,但它不允许我从 getDocumentsDirectory 方法显式创建数组。 是的,这行得通,非常感谢你看到这一点,我永远不会。是的,我非常了解 Swift,并且已经使用它三年了,但是我要回去学习 ObjC,以寻找具有旧版应用程序的工作前景。无论如何,我真的很感谢你的帮助! 我强烈建议使用现代 ObjC 语法——在 Swift 中几乎相同——比如 paths[0] 而不是 [paths objectAtIndex:0]dict[@"key"] 而不是 [dict objectForKey:@"key"] 以及文字数组和字典初始化器 @ 987654332@和@ key:value, key:value;【参考方案2】:

像这样确保文档路径有效

 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentsDirectory = [paths objectAtIndex:0];

 filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpg",uuid]];

【讨论】:

刚刚尝试过,尽管它几乎完全是 getDocumentsDirectory 所做的。它没有改变任何东西。 我解决了但你没有得到它,我的代码与你接受的答案相似 你是对的。首先,我很难找到所写内容之间的区别。不过,我将保留另一个答案,因为它解释了问题所在。

以上是关于创建到文档目录的路径会导致 NSInvalidArgumentException 和无法识别的选择器问题的主要内容,如果未能解决你的问题,请参考以下文章

iOS,将文件从Inbox文件夹复制到文档路径

Flutter:在外部存储路径上创建目录 - 路径提供程序 getExternalStorageDirectory()

Perl File::Copy::Recursive fcopy 不在 UNC 路径上创建目录

我可以在颤振应用程序中保存本地磁盘数据库吗?文档目录在哪里创建路径?

在存word文档时,为啥会出现网络或路径不可用

idea上用api创建一个目录