最近在做云相册的功能,把相册的照片上传到云端,但是上传大照片的时候会报内存警告,有时也会发生崩溃现象。比如我的ipod-touch照的一张全景图片有8.3MB,刚要开始上传就报内存警告。我试过通过处理照片把照片把它的宽高各减少一半,然后再上传,但是还会是有内存警告,因为需要把这张照片全部加载到内存才能进行处理。怎么才能避免内存警告是我们接下来讨论的问题。
-
通过查看API找到出路
上传照片库里的照片,我们需要用到ALAsset这个类,查看其api可以找到如下几个方法来获取图片:
-
- (CGImageRef)thumbnail;
-
- (CGImageRef)aspectRatioThumbnail;
-
[[asset defaultRepresentation] fullResolutionImage];
-
[[asset defaultRepresentation]CGImageWithOptions:(NSDictionary *)options];
前三个想必很容易理解,可以立马排除掉,剩下的希望就只剩下第四个方法了。但是第四个文档上说的不是很清楚,在苹果的api文档上面搜索也没相应的demo。在百度上搜索CGImageWithOptions,看了好多博客都只是提到了CGImageWithOptions,但是并没有详细介绍其如何应用。然后我又在谷歌上搜索,谷歌上搜索也很少,只有5页搜索结果,经过我自己想拜读各个博客,总算在一个角落里找到了个如何使用的链接,通过链接找到了如何使用的文章。废话不多说了,下面给出代码。
#import <ImageIO/ImageIO.h>
// Helper methods for thumbnailForAsset:maxPixelSize:
static
size_t
getAssetBytesCallback(
void
*info,
void
*buffer, off_t position,
size_t
count)
{
ALAssetRepresentation *rep = (__bridge id)info;
NSError *error = nil;
size_t
countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];
if
(countRead == 0 && error) {
// We have no way of passing this info back to the caller, so we log it, at least.
NSLog(@
"thumbnailForAsset:maxPixelSize: got an error reading an asset: %@"
, error);
}
return
countRead;
}
static
void
releaseAssetCallback(
void
*info)
{
// The info here is an ALAssetRepresentation which we CFRetain in thumbnailForAsset:maxPixelSize:.
// This release balances that retain.
CFRelease(info);
}
// Returns a UIImage for the given asset, with size length at most the passed size.
// The resulting UIImage will be already rotated to UIImageOrientationUp, so its CGImageRef
// can be used directly without additional rotation handling.
// This is done synchronously, so you should call this method on a background queue/thread.
- (UIImage *)thumbnailForAsset:(ALAsset *)asset maxPixelSize:(NSUInteger)size
{
NSParameterAssert(asset != nil);
NSParameterAssert(size > 0);
ALAssetRepresentation *rep = [asset defaultRepresentation];
CGDataProviderDirectCallbacks callbacks =
{
.version = 0,
.getBytePointer = NULL,
.releaseBytePointer = NULL,
.getBytesAtPosition = getAssetBytesCallback,
.releaseInfo = releaseAssetCallback,
};
CGDataProviderRef provider = CGDataProviderCreateDirect((
void
*)CFBridgingRetain(rep), [rep size], &callbacks);
CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef)
@{
(NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(NSString *)kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithInt:size],
(NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES,
});
CFRelease(source);
CFRelease(provider);
if
(!imageRef) {
return
nil;
}
UIImage *toReturn = [UIImage imageWithCGImage:imageRef];
CFRelease(imageRef);
return
toReturn;
}