解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
本文轉載至?http://www.superqq.com/blog/2015/01/22/jie-jue-mwphotobrowserzhong-de-sdwebimagejia-zai-da-tu-dao-zhi-de-nei-cun-jing-gao-wen-ti/
MWPhotoBrowser是一個非常不錯的照片瀏覽器,在github的star接近3000個,MWPhotoBrowser下載
MWPhotoBrowser來加載小圖1M以下的都應該不會有內存警告的問題。如果遇到大圖,3M、4M、5M的大圖,很有可能導致內存警告。最近我就遇到這個問題,很是頭疼。來回滑動查看照片內存飆到100M以上:
?
網上查了很多資料,都沒有解決問題。
我們來看一下MWPhotoBrowser,其實MWPhotoBrowser用的是SDWebImage來下載圖片的。SDWebImage下載
在github看到SDWebImage的介紹,后面說到:
Future Enhancements
?
? ? LRU memory cache cleanup instead of reset on memory warning
看到這個真是欲哭無淚啊。
再去看看SDWebImage的,有個人提問了:
How to disable "memory cache"?? I don't want memory cache,? it used a lot of memory and got memory waring easily,? disk is enough for me...
有人回答:
There is no way to disable the memory cache. But the cache is designed to flush itself when you get a memory warning, so you shouldn't need to worry it.
說的是SDWebImage遇到內存警告會自動釋放內存,但是這還是解決不了問題,加載大圖的時候,內存會突然蹦到100多M,在4s及以下的手機上跑,再就掛了。
還是沒有解決內存警告的問題。怎么辦呢?
我是這么解決的:
SDWebImage有一個SDWebImageDownloaderOperation類來執行下載操作的。里面有個下載完成的方法:
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
?? SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock;
?? @synchronized(self) {
?? ? ? CFRunLoopStop(CFRunLoopGetCurrent());
?? ? ? self.thread = nil;
?? ? ? self.connection = nil;
?? ? ? [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:nil];
?? }
?
?? if (![[NSURLCache sharedURLCache] cachedResponseForRequest:_request]) {
?? ? ? responseFromCached = NO;
?? }
?
?? if (completionBlock)
?? {
?? ? ? if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) {
?? ? ? ? ? completionBlock(nil, nil, nil, YES);
?? ? ? }
?? ? ? else {
?? ? ? ? ? UIImage *image = [UIImage sd_imageWithData:self.imageData];
?? ? ? ? ? NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL];
?? ? ? ? ? image = [self scaledImageForKey:key image:image];
?
?? ? ? ? ? // Do not force decoding animated GIFs
?? ? ? ? ? if (!image.images) {
?? ? ? ? ? ? ? image = [UIImage decodedImageWithImage:image];
?? ? ? ? ? }
?? ? ? ? ? if (CGSizeEqualToSize(image.size, CGSizeZero)) {
?? ? ? ? ? ? ? completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}], YES);
?? ? ? ? ? }
?? ? ? ? ? else {
?? ? ? ? ? ? ? completionBlock(image, self.imageData, nil, YES);
?? ? ? ? ? }
?? ? ? }
?? }
?? self.completionBlock = nil;
?? [self done];
}
其中,UIImage *image = [UIImage sd_imageWithData:self.imageData];就是將data轉換成image。
再看看sd_imageWithData:這個方法:
+ (UIImage *)sd_imageWithData:(NSData *)data {
?? UIImage *image;
?? NSString *imageContentType = [NSData sd_contentTypeForImageData:data];
?? if ([imageContentType isEqualToString:@"image/gif"]) {
?? ? ? image = [UIImage sd_animatedGIFWithData:data];
?? }
#ifdef SD_WEBP
?? else if ([imageContentType isEqualToString:@"image/webp"])
?? {
?? ? ? image = [UIImage sd_imageWithWebPData:data];
?? }
#endif
?? else {
?? ? ? image = [[UIImage alloc] initWithData:data];
?? ? ? UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
?? ? ? if (orientation != UIImageOrientationUp) {
?? ? ? ? ? image = [UIImage imageWithCGImage:image.CGImage
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? scale:image.scale
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? orientation:orientation];
?? ? ? }
?? }
?
?
?? return image;
}
這個方法在UIImage+MultiFormat里面,是UIImage的一個類別處理。這句話很重要image = [[UIImage alloc] initWithData:data]; SDWebImage把下載下來的data直接轉成image,然后沒做等比縮放直接存起來使用。所以,我們只需要在這邊做處理即可:
UIImage+MultiFormat添加一個方法:
+(UIImage *)compressImageWith:(UIImage *)image
{
?? float imageWidth = image.size.width;
?? float imageHeight = image.size.height;
?? float width = 640;
?? float height = image.size.height/(image.size.width/width);
?
?? float widthScale = imageWidth /width;
?? float heightScale = imageHeight /height;
?
?? // 創建一個bitmap的context
?? // 并把它設置成為當前正在使用的context
?? UIGraphicsBeginImageContext(CGSizeMake(width, height));
?
?? if (widthScale > heightScale) {
?? ? ? [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)];
?? }
?? else {
?? ? ? [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)];
?? }
?
?? // 從當前context中創建一個改變大小后的圖片
?? UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
?? // 使當前的context出堆棧
?? UIGraphicsEndImageContext();
?
?? return newImage;
?
}
然后在:image = [[UIImage alloc] initWithData:data];下面調用以下:
if (data.length/1024 > 1024) {
?? ? ? ? ? image = [self compressImageWith:image];
?? ? ? }
當data大于1M的時候做壓縮處理。革命尚未成功,還需要一步處理。在SDWebImageDownloaderOperation的connectionDidFinishLoading方法里面的:
? UIImage *image = [UIImage sd_imageWithData:self.imageData];
?
? //將等比壓縮過的image在賦在轉成data賦給self.imageData
? NSData *data = UIImageJPEGRepresentation(image, 1);
? self.imageData =? [NSMutableData dataWithData:data];
大工告成,我們來看一下效果吧:
?
果然問題得以解決。
更多iOS開發相關技術請關注iOS開發微信公眾號 iOS開發 :
iOSDevTip
Posted by 李剛 Jan 22nd, 2015 11:23 am ios開發
本文出處剛剛在線:http://www.superqq.com/blog/2015/01/22/jie-jue-mwphotobrowserzhong-de-sdwebimagejia-zai-da-tu-dao-zhi-de-nei-cun-jing-gao-wen-ti/
?
自由轉載-請在開頭注明本文出處。
轉載于:https://www.cnblogs.com/Camier-myNiuer/p/5100721.html
總結
以上是生活随笔為你收集整理的解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gulp build
- 下一篇: 1.3.3 改善后的异常处理