IOS调用系统相机时,didFinishPickingMediaWithInfo获取不到Asset

今天本来想做服务器SSL证书部署的,但是项目发现了一个问题没时间去做了,晚上剩一点点时间就把这个问题记录一下。

当调用系统相机时,在imagePickerController回调时会获取不到Asset。
在didFinishPickingMediaWithInfo里可以直接拿到image对象,一般情况下直接返回image就可以了,根本不需要用到Asset,所以我对Asset也并不是非常了解。
原来的代码里Asset主要用来获取图片的原始Data并返回,由于代码不规范,当Asset为空时就没有回调了,所以才能够发现这个问题。

由于之前用的是ALAssetsLibrary,当时还以为是因为ALAssetsLibrary被废弃而造成的BUG。但是当我将ALAssetsLibrary替换成<Photos/Photos.h>时,这个问题仍然存在。

当我查了一遍度娘后,我猜测:
1、Asset是相当于相册中的图片的资源文件或者能标记对应图片的标识文件。
2、在使用相机拍摄后,当点击“使用照片”按钮时,图片并没有存在相册里,所以就没有生成对应的资源文件。

所以当点击"使用照片",触发了imagePickerController的didFinishPickingMediaWithInfo方法时,无法获取Asset。

经过尝试,只需要在didFinishPickingMediaWithInfo方法中判断Asset,如果Asset为nil则将图片储存,然后再进行一次获取Asset的操作。

#pragma mark - FinishPick -选择照片回调
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info
{
    WS(weakSelf);
    [picker dismissViewControllerAnimated:YES completion:nil];
    UIImage * image = [[UIImage alloc]init];
    __block PHAsset *phAsset = [[PHAsset alloc]init];
    image = [info valueForKey:UIImagePickerControllerOriginalImage];
    phAsset = [self getPHAssetWithInfo:info LocalIdentifier:nil];
    if (phAsset == nil) {
        [self saveImage_Obj:image completion:^(BOOL success, NSError * _Nullable error, NSString * _Nullable localIdentifier) {
            if (success) {
                phAsset = [self getPHAssetWithInfo:info LocalIdentifier:localIdentifier];
            }
            if (!success || phAsset == nil) {
                if (weakSelf.getPickImage != nil) {
                    weakSelf.getPickImage(image,nil);
                }
                return;
            }
            [self getImageData:phAsset completion:^(NSData *imageData) {
                if (weakSelf.getPickImage != nil) {
                    weakSelf.getPickImage(image,imageData);
                }
            }];
        }];
    }
    else
    {
        [self getImageData:phAsset completion:^(NSData *imageData) {
            if (weakSelf.getPickImage != nil) {
                weakSelf.getPickImage(image,imageData);
            }
        }];
    }
}
#pragma mark - 获取PHAsset
-(PHAsset *)getPHAssetWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info LocalIdentifier:(NSString *)localIdentifier
{
    PHAsset *phAsset = [[PHAsset alloc]init];
    if (@available(iOS 11.0, *)) {
        phAsset = [info valueForKey:UIImagePickerControllerPHAsset];
    } else {
        // Fallback on earlier versions
        NSURL * imageURL = [info valueForKey:UIImagePickerControllerMediaURL];
        PHFetchResult *fetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil];
        phAsset = fetchResult.firstObject;
        
    }
    return phAsset;
}
#pragma mark - 获取图片Data
-(void)getImageData:(PHAsset *)phAsset completion:(nullable void(^)(NSData * imageData))completion
{
    PHImageRequestOptions * imageRequest = [[PHImageRequestOptions alloc]init];
    imageRequest.version = PHImageRequestOptionsVersionUnadjusted;
    
    [[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:imageRequest resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
        if (completion != nil) {
            completion(imageData);
        }
    }];
}
#pragma mark - CancelPick -取消选择回调
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [picker dismissViewControllerAnimated:YES completion:nil];
}

另外今天把这个系统相册、相机的方法都更新了一下,顺便一起发上来吧~

#pragma mark - 使用相册
-(void)UsePhotographAlbum:(GetPickController)getPickController
{
    UIImagePickerController *pick = [[UIImagePickerController alloc]init];
    pick.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    pick.delegate = self;
    [self checkPHAuthorizationStatusWithAllowToUse:^{
        if (getPickController != nil) {
            getPickController(pick,nil);
        }
    }];
}
#pragma mark - 使用相机
-(void)UseCamera:(GetPickController)getPickController
{
    UIImagePickerController *pick = [[UIImagePickerController alloc]init];
    pick.sourceType = UIImagePickerControllerSourceTypeCamera;
    pick.delegate = self;
    
    [self checkAVAuthorizationStatusWithAllowToUse:^{
        if (getPickController != nil) {
            getPickController(pick,nil);
        }
    }];
}
#pragma mark - 保存视频
- (void)saveVideo:(NSURL *)videoUrl
       completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
{
    WS(weakSelf);
    [self checkPHAuthorizationStatusWithAllowToUse:^{
        [weakSelf saveVideo:videoUrl completion:^(BOOL success, NSError * _Nullable error) {
            if (completion != nil) {
                completion(success,error);
            }
        }];
    }];
}
#pragma mark - 保存图片
- (void)saveImage:(UIImage *)image
       completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
{
    WS(weakSelf);
    [self checkPHAuthorizationStatusWithAllowToUse:^{
        [weakSelf saveImage_Obj:image completion:^(BOOL success, NSError * _Nullable error, NSString * _Nonnull localIdentifier) {
            if (completion != nil) {
                completion(success,error);
            }
        }];
    }];
}
#pragma mark - 保存GIF
- (void)saveGIF:(NSString *)gifKey
     completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
{
    WS(weakSelf);
    [self checkPHAuthorizationStatusWithAllowToUse:^{
        NSString * gifPath = [[SDImageCache sharedImageCache] defaultCachePathForKey:gifKey];
        NSURL * gifUrl = gifPath.length>0?[NSURL URLWithString:gifPath]:[NSURL URLWithString:gifKey];
        [weakSelf saveImage_Obj:gifUrl completion:^(BOOL success, NSError * _Nullable error, NSString * _Nonnull localIdentifier) {
            if (completion != nil) {
                completion(success,error);
            }
        }];
    }];
}
#pragma mark - 保存图片方法
-(void)saveImage_Obj:(id)image_Obj
       completion:(nullable void(^)(BOOL success, NSError *__nullable error, NSString *__nullable localIdentifier))completion
{
    // 1. 获取相片库对象
    PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
    //占位对象
    __block PHObjectPlaceholder * placeholder;
    
    // 2. 调用changeBlock
    [library performChanges:^{
        
        // 2.1 创建一个相册变动请求
        PHAssetCollectionChangeRequest *collectionRequest;
        
        // 2.2 取出指定名称的相册
        PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName];
        
        // 2.3 判断相册是否存在
        if (assetCollection) {
            // 如果存在就使用当前的相册创建相册请求
            collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        } else {
            // 如果不存在, 就创建一个新的相册请求
            collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName];
        }
        
        // 2.4 根据传入的相片, 创建相片变动请求
        PHAssetChangeRequest *assetRequest;
        if ([image_Obj isKindOfClass:[UIImage class]]) {
            //如果是图片类型
            assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:(UIImage *)image_Obj];
        }
        else if ([image_Obj isKindOfClass:[NSURL class]])
        {
            //如果是URL类型
            assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:(NSURL *)image_Obj];
        }
        else
        {
            completion(NO,nil,nil);
            return;
        }
        
        // 2.4 创建一个占位对象
        placeholder = [assetRequest placeholderForCreatedAsset];
        
        // 2.5 将占位对象添加到相册请求中
        [collectionRequest insertAssets:@[placeholder] atIndexes:[NSIndexSet indexSetWithIndex:0]];
        
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        
        // 3. 回调
        if (completion != nil) {
            completion(success,error,placeholder.localIdentifier);
        }
    }];
}
#pragma mark - 保存视频方法
-(void)saveVideoWithURL:(NSURL *)video_Url
          completion:(nullable void(^)(BOOL success, NSError *__nullable error))completion
{
    // 1. 获取相片库对象
    PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
    // 2. 调用changeBlock
    [library performChanges:^{
        
        // 2.1 创建一个相册变动请求
        PHAssetCollectionChangeRequest *collectionRequest;
        
        // 2.2 取出指定名称的相册
        PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName];
        
        // 2.3 判断相册是否存在
        if (assetCollection) {
            // 如果存在就使用当前的相册创建相册请求
            collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
        } else {
            // 如果不存在, 就创建一个新的相册请求
            collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName];
        }
        
        // 2.4 根据传入的相片, 创建相片变动请求
        PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:video_Url];
        
        // 2.4 创建一个占位对象
        PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset];
        
        // 2.5 将占位对象添加到相册请求中
        [collectionRequest insertAssets:@[placeholder] atIndexes:[NSIndexSet indexSetWithIndex:0]];
        
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        
        // 3. 回调
        if (completion != nil) {
            completion(success,error);
        }
    }];
}
#pragma mark - 获取相册名称
-(PHAssetCollection *)getCurrentPhotoCollectionWithTitle:(NSString *)collectionName {
    
    // 1. 创建搜索集合
    PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    
    // 2. 遍历搜索集合并取出对应的相册
    for (PHAssetCollection *assetCollection in result) {
        
        if ([assetCollection.localizedTitle containsString:collectionName]) {
            return assetCollection;
        }
    }
    
    return nil;
}
#pragma mark - 检查相册权限
-(void)checkPHAuthorizationStatusWithAllowToUse:(nullable void(^)(void))allowToUse
{
    // 1. 获取当前App的相册授权状态
    PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
    
    // 2. 判断授权状态
    if (authorizationStatus == PHAuthorizationStatusAuthorized && allowToUse != nil) {
        allowToUse();
    } else if (authorizationStatus == PHAuthorizationStatusNotDetermined) { // 如果没决定, 弹出指示框, 让用户选择
        
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            
            // 如果用户选择授权, 则保存图片
            if (status == PHAuthorizationStatusAuthorized && allowToUse != nil) {
                allowToUse();
            }
        }];
        
    } else {
        UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置->隐私->照片中开启【华世界商圈】的对应权限,以便于我们能够存取您的图像信息。" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * OK_Action = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            if (@available(iOS 10.0, *)) {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success)
                 {
                     
                 }];
            } else {
                //iOS10以前,使用旧API
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
            }
        }];
        [alertController addAction:OK_Action];
        
        UIAlertAction * Cancel_Action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            [[AppDelegate lastWindow].viewController.navigationController popViewControllerAnimated:YES];
        }];
        [alertController addAction:Cancel_Action];
        [[AppDelegate lastWindow].rootViewController presentViewController:alertController animated:YES completion:nil];
    }
}
#pragma mark - 检查相机权限
-(void)checkAVAuthorizationStatusWithAllowToUse:(nullable void(^)(void))allowToUse
{
    //判断是否有相机权限
    AVAuthorizationStatus authorizationStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];//读取设备授权状态
    if (authorizationStatus == AVAuthorizationStatusAuthorized && allowToUse != nil) {
        allowToUse();
    }
    else if(authorizationStatus == AVAuthorizationStatusNotDetermined){
        [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            if (granted == YES && allowToUse != nil) {
                allowToUse();
            }
        }];
    } else {
        UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置->隐私->相机中开启【华世界商圈】的使用权限,以便于我们能够使用您的相机进行拍摄或扫描。" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction * OK_Action = [UIAlertAction actionWithTitle:@"设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            if (@available(iOS 10.0, *)) {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:^(BOOL success)
                 {
                     
                 }];
            } else {
                //iOS10以前,使用旧API
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
            }
        }];
        [alertController addAction:OK_Action];
        
        UIAlertAction * Cancel_Action = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
            [[AppDelegate lastWindow].viewController.navigationController popViewControllerAnimated:YES];
        }];
        [alertController addAction:Cancel_Action];
        [[AppDelegate lastWindow].rootViewController presentViewController:alertController animated:YES completion:nil];
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335