再谈PhotoKit

PhotoKit作为iOS8新推出的照片库,相比较于之前的ALAssetsLibrary确实解决了不少问题,那么结合我最近的使用,也借鉴了"TZImagePickerController"、"CTAssetsPickerController"等流行的开源框架,以及官方的SwiftDemo,来讲讲几个难以察觉的点。

内存问题

自定义相册基本思路都是拿UICollectionView来展示各种列表,那么内存主要就存在于对照片缩略图的获取以及滑动卡顿的问题,我们来看看TZImagePickerController,

__block UIImage *image;
        // 修复获取图片时出现的瞬间内存过高问题
        // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢
        PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
        option.resizeMode = PHImageRequestOptionsResizeModeFast;
        int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
            if (result) {
                image = result;
            }
            BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
            if (downloadFinined && result) {
                result = [self fixOrientation:result];
                if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
            }
            // Download image from iCloud / 从iCloud下载图片
            if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) {
                PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
                options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        if (progressHandler) {
                            progressHandler(progress, error, stop, info);
                        }
                    });
                };
                options.networkAccessAllowed = YES;
                options.resizeMode = PHImageRequestOptionsResizeModeFast;
                [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
                    UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
                    resultImage = [self scaleImage:resultImage toSize:imageSize];
                    if (!resultImage) {
                        resultImage = image;
                    }
                    resultImage = [self fixOrientation:resultImage];
                    if (completion) completion(resultImage,info,NO);
                }];
            }
        }];

注释有提到修复了瞬间内存过高,但测试发现iPad mini上快速滑动依然会有内存警告最终导致Crash。(CTAssetsPickerController同样如此)这里PHImageRequestOptionsResizeModeFast设置,会有两次结果回调,一次模糊,一次清晰(如果有的话),一般来说没什么问题。有说可以通过requestImageDataForAsset解决,没错这种方式内存占用确实要小不少,但Data到Image这一步需要做不少处理吧,并没有之前的API那么方便。我的结论是将contentMode改为PHImageContentModeAspectFit,同时尽量利用PHCachingImageManager来做缓存,这样效果会好很多。

iCloud问题

目前的系统设置有几个选项,针对用户开启了iCloud照片库,并且选择了“优化iPhone/iPad存储空间”或者选择了“下载并保留原件”但原件还未加载出来,也就是说资源不在本地。PHImageRequestOptions或者PHVideoRequestOptions在开启了PHVideoRequestOptions,会试图从iCloud去下载资源,这时候耗时可能会很长,另外也可能载入不成功,这两点都必须有严格的过度处理。这两点在之前的两个开源库中都有体现。而在我们开发中,大部分可能都忽视了这一点。

相册变更

这个主要是系统相册的增删,或者iCloud的更新对自定义相册的影响。原本是参考官方Swif版本来进行处理,没想到坑就在这里,同时更新和删除会Crash,官方Demo也不例外。主要是在performBatchUpdates这个地方。造成了线上好些崩溃记录。目前的处理如下

    if (changes == nil) {
        return;
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        
        self.allVideos = changes.fetchResultAfterChanges;
        
        UICollectionView *collectionView = self.collectionView;
        
        if (!changes.hasIncrementalChanges || changes.hasMoves)
        {
            [collectionView reloadData];
            [self fixupSelection];
            [self resetCachedAssets];
        }
        else
        {
            NSArray *removedPaths;
            NSArray *insertedPaths;
            NSArray *changedPaths;
            
            NSIndexSet *removedIndexes = changes.removedIndexes;
            removedPaths = [removedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0];
            
            NSIndexSet *insertedIndexes = changes.insertedIndexes;
            insertedPaths = [insertedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0];
            
            NSIndexSet *changedIndexes = changes.changedIndexes;
            changedPaths = [changedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0];
            
            BOOL shouldReload = NO;
            
            if (changedPaths != nil && removedPaths != nil)
            {
                for (NSIndexPath *changedPath in changedPaths)
                {
                    if ([removedPaths containsObject:changedPath])
                    {
                        shouldReload = YES;
                        break;
                    }
                }
            }
            
            if (removedPaths.lastObject && ((NSIndexPath *)removedPaths.lastObject).item >= self.allVideos.count)
            {
                shouldReload = YES;
            }
            
            if (shouldReload)
            {
                [collectionView reloadData];
                [self fixupSelection];
            }
            else
            {
                [collectionView performBatchUpdates:^{
                    if (removedPaths.count)
                    {
                        [collectionView deleteItemsAtIndexPaths:[removedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0]];
                    }
                    
                    if (insertedPaths.count)
                    {
                        [collectionView insertItemsAtIndexPaths:[insertedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0]];
                    }
                    
                    if (changedPaths.count)
                    {
                        [collectionView reloadItemsAtIndexPaths:[changedIndexes vk_assetGridIndexPathsFromIndexesWithSection:0] ];
                    }
                } completion:^(BOOL finished){
                    if (finished) {
                        [self resetCachedAssets];
                        [self fixupSelection];
                    }
                }];
            }
        }
        
        [self.emptyView setHidden:self.allVideos.count > 0];
        
    });

视频封面截取帧

封面要求截取9张图片,之前有通过循环一次性截取9张图片,但这个操作有些耗时,看到系统有AVAssetImageGenerator,所以采用了这种方案。但这个API有一个问题,传入的Times数组是9个值,回调时并不一定给你回调9次,有可能更多,所以在回调时候最好做一些边界处理。

以上就是这次使用遇到的一系列问题。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,960评论 3 119
  • (七) 一条道路延伸到远方,又消失在远方来往的人影和车辆之中,使得我看不清楚它的尽头。车辆来来往往,人们走走停停,...
    说鱼之乐阅读 333评论 0 0
  • 一条生活馆 客服与订单 福庆叔叔 明前龙井 | 不施农药化肥的杭州午潮山自然茶园 ¥369.00 ¥ 需要帮助?立...
    山丘工作室阅读 272评论 0 0
  • 曹禺在【雷雨.序】 中写的话: 我念起人类是怎样可怜的动物,带着踌躇满志的心情仿佛自己来主宰自己的...
    暗夜撄宁阅读 395评论 0 0
  • 自己生活了三十几年,但又目标的活着的时候应该不超过一年,或者说没有被别人逼着自己往前走的时候而有目标往前走时应该不...
    你好3306阅读 196评论 0 0