1.首先说第一个坑
我们项目是一个老的项目图片选择,浏览都是用的ALAssetsLibrary
这个框架,但是自从iOS8之后就废弃了,以至于引来了现在的问题,突然有一天公司一个老总问我,在他手机里面选择照片的时候,打开相册只显示几张照片,当时我一脸懵逼,我他么的怎么知道这是砸回事,手机有毛病吧可能,于是开始查资料,后来没解决,再突然有一天公司又来了一个测试人员,她的手机也是相册只显示几张图片,我开始重视这个问题了,于是开始认真查资料,同时此bug被列为一级bug,不得不解决.
查了半天终于有点眉目,原来ALAssetsLibrary
这个框架是不能获取iCloud里面的图片,而PhotoKit
这个框架可以,就两行代码PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.networkAccessAllowed = YES;
就是这个YES 允许了下载ICloud上面的图片.
2.第二个坑:先看一段代码如下
for(PHAsset *asset in self.assets) {
// This autorelease pool seems good (a1)
@autoreleasepool {
NSLog(@"started requesting image %i", i);
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:[self imageRequestOptions] resultHandler:^(UIImage *image, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
//you can add autorelease pool here as well (a2)
@autoreleasepool {
assetCount++;
NSError *error = [info objectForKey:PHImageErrorKey];
if (error) NSLog(@"Image request error: %@",error);
else {
NSString *imagePath = [appDelegate.docsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%i.png",i]];
NSData *imageData = UIImagePNGRepresentation(image);
if(imageData) {
[imageData writeToFile:imagePath atomically:YES];
[self.imagesArray addObject:imagePath];
}
else {
NSLog(@"Couldn't write image data to file.");
}
[self checkAddComplete];
NSLog(@"finished requesting image %i", i);
}
} //a2 ends here
});
}];
i++;
} // a1 ends here
}
这段代码是我在stackoverflow上看到的,此代码的功能是遍历相册里面所有的图片,然后遍历出UIImage对象(我遇到的问题是遍历的过程中假如一下子遍历上百张图片内存会暴涨,达到了1.1G,然后崩溃)与我写的代码一对比就是比我多写了一个自动释放池,我照他的代码多加一个
autoreleasepool
问题依旧没解决,继续查资料,看API,我发现了一个与requestImageForAsset
方法很像的方法:requestImageDataForAsset
,两者差别就是UIImage和NSData,这个api是快下班的时候看到的当时感觉没用,就没去尝试,第二天查资料有人说跟它可能有关系,原因是直接遍历出UIImage对象的时候会造成图片渲染,而requestImageDataForAsset这个方法不会,于是尝试一番,结果让我喜出望外,一下子选择100张图片上传,内存最多不超过200,我感觉还可以,于是就先这样吧,问题解决了.
3.第三个问题PHImageManagerMaximumSize 这个api的意思就是遍历图片时获取原图尺寸,如果你要是想九宫格那个显示的,最好把它改为CGSize(100,100),自己定一个尺寸,内存也不会飙升了
问题总结:利用好自动释放池autoreleasepool,做到内存及时释放,查找造成内存暴涨的代码,分段注释查找,很容易找到,还有遇到感觉可以解决问题的api,一定要多try几次,实践出真知!
下面附上正确的代码:
-(void)reloadImageData
{
MJWeakSelf;//此宏是MJ刷新自带的一个快速定义一个WeakSelf
for(int i=0;i<_assetArray.count;i++){
NSDictionary *dic = [_dataList objectAtIndex:i];
NSString *imgUrl = [dic objectForKey:@"imgUrl"];
@autoreleasepool {
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.synchronous = YES;
PHFetchResult *phFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[imgUrl] options: nil ];
[phFetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx,BOOL *_Nonnull stop) {
NSLog(@"obj======%@",obj);
PHAsset * asset = obj;
@autoreleasepool {
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info)
{
dispatch_async(dispatch_get_main_queue(), ^{
@autoreleasepool {
UIImage *image = [UIImage imageWithData:imageData];;
[weakSelf.dataList addObject:image];
}
});
}];
}
}];
}
}
<PHFetchResult *phFetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[imgUrl] options: nil ];
讲一下这行代码,这段代码的意思是通过图片的一个图片的LocalIdentifier(唯一标识符来)查找相册里面的图片,当时想用PHAsset
另外一个方法:fetchAssetsWithALAssetURLs
通过URL来找本地的图片,但是怕他有时候找不到URL,不靠谱于是就用了fetchAssetsWithLocalIdentifiers
它.
有什么讲解不对的地方欢迎指正,一起进步,谢谢