Reputation: 127
I'm a newbie to ios development. I'm trying to follow the official documentation of Firebase to implement an image uploading function. But I encountered the following error:
2018-07-20 17:27:43.084497-0700 Geographical_Photo_Map[71118:36381409] -[NSURL _fastCStringContents:]: unrecognized selector sent to instance 0x6040012f2380
2018-07-20 17:27:43.090438-0700 Geographical_Photo_Map[71118:36381409] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL _fastCStringContents:]: unrecognized selector sent to instance 0x6040012f2380'
*** First throw call stack:
(
0 CoreFoundation 0x000000011271712b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000011185ef41 objc_exception_throw + 48
2 CoreFoundation 0x0000000112798024 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x0000000112699f78 ___forwarding___ + 1432
4 CoreFoundation 0x0000000112699958 _CF_forwarding_prep_0 + 120
5 libsystem_trace.dylib 0x00000001138ac70b os_log_shim_with_CFString + 66
6 CoreFoundation 0x00000001126ed96f _CFLogvEx3 + 239
7 Foundation 0x000000011088030b _NSLogv + 104
8 Foundation 0x000000011086c023 NSLog + 132
9 Geographical_Photo_Map 0x000000010f119c08 -[ViewController imagePickerController:didFinishPickingMediaWithInfo:] + 216
10 UIKit 0x0000000113e36def -[UIImagePickerController _imagePickerDidCompleteWithInfo:] + 127
11 UIKit 0x0000000113e36709 __60-[UIImagePickerController didSelectMediaWithInfoDictionary:]_block_invoke + 42
12 libdispatch.dylib 0x00000001135c12f7 _dispatch_call_block_and_release + 12
13 libdispatch.dylib 0x00000001135c233d _dispatch_client_callout + 8
14 libdispatch.dylib 0x00000001135cd5f9 _dispatch_main_queue_callback_4CF + 628
15 CoreFoundation 0x00000001126d9e39 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
16 CoreFoundation 0x000000011269e462 __CFRunLoopRun + 2402
17 CoreFoundation 0x000000011269d889 CFRunLoopRunSpecific + 409
18 GraphicsServices 0x0000000117eb99c6 GSEventRunModal + 62
19 UIKit 0x00000001139db5d6 UIApplicationMain + 159
20 Geographical_Photo_Map 0x000000010f11b19f main + 111
21 libdyld.dylib 0x000000011363ed81 start + 1
)
I tried to debug, now seems that the exception happens in this place:
//NSURL *localFile = [NSURL URLWithString: path];
NSURL *localFile = path;
I tried both of them, both none of them seems to be working.
My full code:
// This method is called when an image has been chosen from the library or taken from the camera.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//You can retrieve the actual UIImage
UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
//Or you can get the image url from AssetsLibrary
NSURL *path = [info valueForKey:UIImagePickerControllerReferenceURL];
[picker dismissViewControllerAnimated:YES completion:nil];
NSLog(@"finish choosing image.");
NSLog(path);
// Upload to firebase
// Local file you want to upload
//NSURL *localFile = [NSURL URLWithString: path];
NSURL *localFile = path;
// Create the file metadata
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";
// Get a reference to the storage service using the default Firebase App
FIRStorage *storage = [FIRStorage storage];
// Create a storage reference from our storage service
FIRStorageReference *storageRef = [storage reference];
// Upload file and metadata to the object 'images/mountains.jpg'
FIRStorageUploadTask *uploadTask = [storageRef putFile:localFile metadata:metadata];
// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
}];
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload paused
}];
[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload reported progress
double percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
}];
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload completed successfully
}];
// Errors only occur in the "Failure" case
[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
if (snapshot.error != nil) {
switch (snapshot.error.code) {
case FIRStorageErrorCodeObjectNotFound:
// File doesn't exist
break;
case FIRStorageErrorCodeUnauthorized:
// User doesn't have permission to access file
break;
case FIRStorageErrorCodeCancelled:
// User canceled the upload
break;
case FIRStorageErrorCodeUnknown:
// Unknown error occurred, inspect the server response
break;
}
}
}];
}
- (IBAction)UploadButtonClicked:(id)sender {
// Choose from photo library.
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
Seems like the error is about the format NSURL? But I think the parameters I used is NSURL? I will be greatly appreciated if someone offers any suggestions or solutions!
Upvotes: 3
Views: 628
Reputation: 4569
The stack trace has been clearly indicated which statement made your app crash:
0x000000011086c023 NSLog + 132
You have misused NSLog
function as follow:
NSURL *path = [info valueForKey:UIImagePickerControllerReferenceURL];
[picker dismissViewControllerAnimated:YES completion:nil];
NSLog(@"finish choosing image.");
NSLog(path); // <---- This statement make you crash
You can't directly pass a NSURL
parameter to NSLog
function, because NSLog
is a C function. The prototype of NSLog
is:
void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL
To fix this issue, you should call it as:
NSLog(@"URL: %@", path);
Upvotes: 0
Reputation: 13283
I am not sure why you're using NSURL
to upload an image, but you can just use (I usually use) NSData
generated directly from a UIImage
, like so:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
// Get the selected image.
UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
// Generate a data from the image selected
NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
// Create the file metadata
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";
// Get a reference to the storage service using the default Firebase App
FIRStorage *storage = [FIRStorage storage];
// Create a storage reference from our storage service
FIRStorageReference *storageRef = [storage reference];
// Upload file and metadata to the object 'images/mountains.jpg'
FIRStorageUploadTask *uploadTask = [storageRef putData:imageData metadata:metadata];
// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
}];
}
In this way (above), you get a change to lower the compression quality of your image before the upload.
Anyways, if you're going to generate a local path of your selected image from the picker, you can use check this out:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
// Get the selected image's NSURL.
NSURL *imagePath = [info objectForKey:@"UIImagePickerControllerReferenceURL"];
NSString *imageName = [imagePath lastPathComponent];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *localFilePathString = [documentsDirectory stringByAppendingPathComponent:imageName];
NSURL *localFile = [NSURL URLWithString:localFilePathString];
// Create the file metadata
FIRStorageMetadata *metadata = [[FIRStorageMetadata alloc] init];
metadata.contentType = @"image/jpeg";
// Get a reference to the storage service using the default Firebase App
FIRStorage *storage = [FIRStorage storage];
// Create a storage reference from our storage service
FIRStorageReference *storageRef = [storage reference];
// Upload file and metadata to the object 'images/mountains.jpg'
FIRStorageUploadTask *uploadTask = [storageRef putFile:localFile metadata:metadata];
// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
}];
}
So I bet that you are generating incorrectly the local path, hence the crash, you're giving a path that contains nil.
I hope this helps!
Upvotes: 1