PhotoKit作為iOS8新推出的照片庫(kù)命斧,相比較于之前的ALAssetsLibrary確實(shí)解決了不少問題辩块,那么結(jié)合我最近的使用,也借鑒了"TZImagePickerController"滞伟、"CTAssetsPickerController"等流行的開源框架腺阳,以及官方的SwiftDemo,來講講幾個(gè)難以察覺的點(diǎn)于置。
內(nèi)存問題
自定義相冊(cè)基本思路都是拿UICollectionView來展示各種列表茧吊,那么內(nèi)存主要就存在于對(duì)照片縮略圖的獲取以及滑動(dòng)卡頓的問題,我們來看看TZImagePickerController俱两,
__block UIImage *image;
// 修復(fù)獲取圖片時(shí)出現(xiàn)的瞬間內(nèi)存過高問題
// 下面兩行代碼饱狂,來自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);
}];
}
}];
注釋有提到修復(fù)了瞬間內(nèi)存過高宪彩,但測(cè)試發(fā)現(xiàn)iPad mini上快速滑動(dòng)依然會(huì)有內(nèi)存警告最終導(dǎo)致Crash。(CTAssetsPickerController同樣如此)這里PHImageRequestOptionsResizeModeFast設(shè)置讲婚,會(huì)有兩次結(jié)果回調(diào)尿孔,一次模糊,一次清晰(如果有的話)筹麸,一般來說沒什么問題活合。有說可以通過requestImageDataForAsset解決,沒錯(cuò)這種方式內(nèi)存占用確實(shí)要小不少物赶,但Data到Image這一步需要做不少處理吧白指,并沒有之前的API那么方便。我的結(jié)論是將contentMode改為PHImageContentModeAspectFit酵紫,同時(shí)盡量利用PHCachingImageManager來做緩存告嘲,這樣效果會(huì)好很多。
iCloud問題
目前的系統(tǒng)設(shè)置有幾個(gè)選項(xiàng)奖地,針對(duì)用戶開啟了iCloud照片庫(kù)橄唬,并且選擇了“優(yōu)化iPhone/iPad存儲(chǔ)空間”或者選擇了“下載并保留原件”但原件還未加載出來,也就是說資源不在本地参歹。PHImageRequestOptions或者PHVideoRequestOptions在開啟了PHVideoRequestOptions仰楚,會(huì)試圖從iCloud去下載資源,這時(shí)候耗時(shí)可能會(huì)很長(zhǎng)犬庇,另外也可能載入不成功僧界,這兩點(diǎn)都必須有嚴(yán)格的過度處理。這兩點(diǎn)在之前的兩個(gè)開源庫(kù)中都有體現(xiàn)臭挽。而在我們開發(fā)中捂襟,大部分可能都忽視了這一點(diǎn)。
相冊(cè)變更
這個(gè)主要是系統(tǒng)相冊(cè)的增刪埋哟,或者iCloud的更新對(duì)自定義相冊(cè)的影響笆豁。原本是參考官方Swif版本來進(jìn)行處理郎汪,沒想到坑就在這里,同時(shí)更新和刪除會(huì)Crash闯狱,官方Demo也不例外煞赢。主要是在performBatchUpdates這個(gè)地方。造成了線上好些崩潰記錄哄孤。目前的處理如下
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張圖片照筑,之前有通過循環(huán)一次性截取9張圖片,但這個(gè)操作有些耗時(shí)瘦陈,看到系統(tǒng)有AVAssetImageGenerator凝危,所以采用了這種方案。但這個(gè)API有一個(gè)問題晨逝,傳入的Times數(shù)組是9個(gè)值蛾默,回調(diào)時(shí)并不一定給你回調(diào)9次,有可能更多捉貌,所以在回調(diào)時(shí)候最好做一些邊界處理支鸡。
以上就是這次使用遇到的一系列問題。