【问题标题】:Upload image from ios device using Firebase - objective c使用 Firebase 从 ios 设备上传图像 - 目标 c
【发布时间】:2018-07-21 22:40:42
【问题描述】:

我是 ios 开发的新手。我正在尝试按照 Firebase 的官方文档来实现图像上传功能。但是我遇到了以下错误:

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
)

我尝试调试,现在好像异常发生在这个地方:

//NSURL *localFile = [NSURL URLWithString: path];
NSURL *localFile = path;

我都试过了,似乎都没有工作。

我的完整代码:

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

似乎错误与格式 NSURL 有关?但是我认为我使用的参数是NSURL?如果有人提供任何建议或解决方案,我将不胜感激!

【问题讨论】:

    标签: ios objective-c firebase


    【解决方案1】:

    我不确定你为什么使用NSURL 来上传图片,但你可以使用(我通常使用)直接从UIImage 生成的NSData,如下所示:

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

    通过这种方式(上图),您可以在上传之前降低图像的压缩质量。

    无论如何,如果您要从选取器中生成所选图像的本地路径,您可以使用检查一下:

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

    所以我敢打赌,您生成的本地路径不正确,因此崩溃,您给出的路径包含 nil。

    我希望这会有所帮助!

    【讨论】:

    • 谢谢,但在尝试了两种解决方案后,日志显示:2018-07-21 17:42:33.306219-0700 Geographical_Photo_Map[330:34159] *** 由于未捕获的异常而终止应用程序'NSInvalidArgumentException',原因:'*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]:尝试从对象 [1] 中插入 nil 对象'libc++abi.dylib:以 NSException (lldb) 类型的未捕获异常终止
    • 似乎还是老问题,nil 值
    • 必须创建子引用才能上传文件,您不能将其上传到根节点 - Firebase 存储文档中对此进行了明确说明。 stackoverflow.com/a/38459616
    【解决方案2】:

    堆栈跟踪已明确指出是哪个语句导致您的应用崩溃:

    0x000000011086c023 NSLog + 132

    你误用了NSLog函数如下:

    NSURL *path = [info valueForKey:UIImagePickerControllerReferenceURL];
    
    [picker dismissViewControllerAnimated:YES completion:nil];
    NSLog(@"finish choosing image.");
    NSLog(path);    // <---- This statement make you crash
    

    您不能直接将NSURL 参数传递给NSLog 函数,因为NSLog 是一个C 函数。 NSLog的原型是:

    void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NS_NO_TAIL_CALL
    

    要解决此问题,您应该将其称为:

    NSLog(@"URL: %@", path);
    

    【讨论】:

    • 谢谢,NSLog 是对的,但那行是我在上传图片后添加的,所以这不是导致图片上传崩溃的原因。不过还是谢谢你的回答!!
    • @Qiaofei 那么你能在没有 NSLog 的情况下将你的实际崩溃日志粘贴到这里吗?
    猜你喜欢
    • 2023-03-27
    • 2012-06-17
    • 1970-01-01
    • 2021-09-10
    • 2012-06-19
    • 2021-10-18
    • 1970-01-01
    • 2015-02-07
    相关资源
    最近更新 更多