-1

I am learning Obj-C, and I cannot for the life of me figure out why I am getting this crash. Here is the error message:

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

Here is the code where it crashes:

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

I am trying to select an image from the ImagePickerController, then save the data to a location on the disk with a UUID. It seems to be crashing when I try to append the UUID to the filePath. I get the filePath from a helper function. What am I doing wrong?

EDIT: Here is the helper function...

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

}
Cody Lucas
  • 682
  • 1
  • 6
  • 23

2 Answers2

2

Please read the error message:

[__NSSingleObjectArrayI stringByAppendingPathComponent:]: unrecognized selector

clearly states that the method getDocumentsDirectory returns an Array, not a single string. So you have to get the first object of the array:

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

Edit:

Your helper method returns an array because you are initializing an array with the result of NSSearchPathForDirectoriesInDomains which is already an array. The result is a nested array

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

and getting the object at index 0 is still an array.


The solution is to change getDocumentsDirectory to

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

then you can keep the syntax

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

PS: I recommend to learn Swift rather than ObjC. The Swift compiler doesn't let you do those type mismatch mess

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Hello. Thank you for your idea. I have edited my post to include the method that is apparently returning an array. I cannot initialize the results of the method into an array because it explicitly returns an NSString. Can you look at the function and tell me how that would be possible? I tried exactly as you spelled and it does not allow me to create an array explicitly from the getDocumentsDirectory method. – Cody Lucas Jan 22 '18 at 21:59
  • Yes, that worked, thank you so much for seeing that, I never would have. And yes, I know Swift very well and have been using it for three years, but I'm going back to learn ObjC for a job prospect that has a legacy app. Anyway, I really appreciate your help! – Cody Lucas Jan 22 '18 at 22:14
  • 1
    I highly recommend to use the modern ObjC syntax – almost the same in Swift – like `paths[0]` instead of `[paths objectAtIndex:0]` or `dict[@"key"]` instead of `[dict objectForKey:@"key"]` and the literal array and dictionary initializers `@[ item, item ];` and `@{ key:value, key:value};` – vadian Jan 22 '18 at 22:23
1

Make sure document path is valid like this

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

 filePath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpg",uuid]];
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Just tried this, even though its almost exactly what the getDocumentsDirectory does. It did not change anything. – Cody Lucas Jan 22 '18 at 21:49
  • 1
    I solved it but you didn't get it , my code is similar to your accepted answer – Shehata Gamal Jan 23 '18 at 07:04
  • 1
    You are right. I had trouble in the first place finding the difference between what was written. I am going to keep the other answer though because it explains what was wrong. – Cody Lucas Jan 23 '18 at 17:13