[英]Upload image from ios device using Firebase - objective c
I'm a newbie to ios development. 我是ios开发的新手。 I'm trying to follow the official documentation of Firebase to implement an image uploading function. 我正在尝试遵循Firebase的官方文档来实现图像上传功能。 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? 似乎错误是关于NSURL格式的? But I think the parameters I used is NSURL? 但是我认为我使用的参数是NSURL? I will be greatly appreciated if someone offers any suggestions or solutions! 如果有人提供任何建议或解决方案,我将不胜感激!
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: 我不知道为什么你使用NSURL
上传图片,但你可以使用(我一般用) NSData
直接从产生UIImage
,就像这样:
- (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. 所以我敢打赌,您错误地生成了本地路径,因此崩溃了,您给出的路径包含nil。
I hope this helps! 我希望这有帮助!
The stack trace has been clearly indicated which statement made your app crash: 堆栈跟踪已明确指出是哪条语句导致您的应用崩溃:
0x000000011086c023 NSLog + 132 0x000000011086c023 NSLog + 132
You have misused NSLog
function as follow: 您误用了NSLog
函数,如下所示:
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. 您不能直接将NSURL
参数传递给NSLog
函数,因为NSLog
是C函数。 The prototype of NSLog
is: NSLog
的原型是:
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.