我尝试修改FGallery(https://github.com/gdavis/FGallery-iPhone)。 我需要它来从相机胶卷读取图像,但我得到内存泄漏。
旧代码(路径是文件位置):
@autoreleasepool {
NSString *path = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] bundlePath],_thumbUrl];
_thumbnail = [UIImage imageWithContentsOfFile:path];
_hasThumbLoaded = YES;
_isThumbLoading = NO;
[self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil waitUntilDone:YES];
}
我的代码(路径是断言库url):
@autoreleasepool {
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
_thumbnail = [UIImage imageWithCGImage:iref];
_hasThumbLoaded = YES;
_isThumbLoading = NO;
[self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil waitUntilDone:YES];
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror) {
NSLog(@"booya, cant get image - %@",[myerror localizedDescription]);
};
NSURL *asseturl = [NSURL URLWithString:_thumbUrl];
[assetslibrary assetForURL:asseturl
resultBlock:resultblock
failureBlock:failureblock];
}
}
对于相同的图像,我得到一个大的内存分配(-didReceiveMemoryWarning),使我的代码中的程序崩溃,但不是在使用原始代码时。
任何想法为什么?
P.S。我使用ARC,并为FGallery进行了自动转换。它适用于本地应用程序图像,但正如所说,我无法使其适用于相机胶卷图像。
编辑1:程序崩溃
答案 0 :(得分:6)
我想我明白了。 “ALAssetsLibraryAssetForURLResultBlock resultblock”正在另一个线程上运行。 因此“@autoreleasepool”不适用于它。 (每个线程都有自己的自动释放池)。因此,由于许多“自动释放”分配(图像),内存占用率要高得多。 在块内添加“@autoreleasepool”可以阻止崩溃和大内存分配。
简而言之:
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
@autoreleasepool {
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
_thumbnail = [UIImage imageWithCGImage:iref];
_hasThumbLoaded = YES;
_isThumbLoading = NO;
[self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil waitUntilDone:YES];
}
}
};
感谢所有回复的人。
答案 1 :(得分:4)
除非需要全分辨率图像,否则最好使用:
CGImageRef iref = [rep fullScreenImage];
此调用返回适合显示全屏的表示形式的CGImage,而不是可用的最大,最佳表示形式,不以任何方式调整。
这样做可以节省大量内存。
答案 2 :(得分:0)
获取内存警告(-didReceiveMemoryWarning)与内存泄漏不同。这只是意味着你分配了大量内存,并且它给系统施加压力,操作系统将此解释为潜在的问题。很快就会发生
当您有未被释放的未引用对象时,会发生内存泄漏。您可以使用编译器分析工具查看潜在泄漏的位置。这不会全部找到,所以你可以使用工具来查看其他任何可能发生的地方。但是,在使用这些工具进行检查之前,您无法确定通过查看代码来确定泄漏情况并不明显。
您没有提及您的代码是否崩溃,但如果是,则不一定是因为内存泄漏。当操作系统决定必须删除某些内容以减少内存压力时,就会发生这种情况。
更新
显示类ALAssetRepresentation的代码。你可能不会在那里发布一些东西。
答案 3 :(得分:0)
正如用户 Picciano 在帖子中提到的那样,如果可能,您应该使用[rep fullScreenImage];
来电而不是请求全尺寸图片。这将节省大量空间。
但是,在我的情况下,这是不可能的,因为我需要稍后将更高分辨率的图像发送到外部服务器。
你可以做的是使用比例尽可能地调整它的大小:
CGFloat originalRatio = assetRepresentation.dimensions.width / assetRepresentation.dimensions.height;
CGFloat wantedRatio = maxSize.width / maxSize.height;
CGFloat scale = 1;
if (originalRatio < wantedRatio)
{
scale = maxSize.height / assetRepresentation.dimensions.height;
}
else
{
scale = maxSize.width / assetRepresentation.dimensions.width;
}
CGImageRef ref = [assetRepresentation fullResolutionImage];
UIImage *image = [UIImage imageWithCGImage:ref
scale:scale orientation:orientation];
这基本上决定了我们可以缩放图像的数量(由maxSize
定义)。这节省了我们足以防止内存泄漏。