SDWebImage加載高清大圖崩潰問題:html
經驗證沒測試出來,在網上查找根源應該是在iOS7上有問題,特此記錄一下ios
第一種:老版本SDWebImage_v4.2.0git
更改源碼github
這裏面對圖片的處理是直接按照原大小進行的,若是幾千是分辨率這裏致使佔用了大量內存。緩存
一、在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; }
二、再在上面箭頭代碼後面對圖片進行壓縮app
image = [[UIImage alloc] initWithData:data]; if (data.length/1024 > 128) { image = [self compressImageWith:image]; }
三、 在SDWebImageDownloaderOperation.m 的 -(void)connectionDidFinishLoading:(NSURLConnection *)aConnection 方法中增長代碼async
-(void)connectionDidFinishLoading:(NSURLConnection *)aConnection { SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock; @synchronized(self) { CFRunLoopStop(CFRunLoopGetCurrent()); self.thread = nil; self.connection = nil; dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:self]; [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadFinishNotification object:self]; }); } if (![[NSURLCache sharedURLCache] cachedResponseForRequest:_request]) { responseFromCached = NO; } if (completionBlock) { if (self.options & SDWebImageDownloaderIgnoreCachedResponse && responseFromCached) { completionBlock(nil, nil, nil, YES); } else if (self.imageData) { UIImage *image = [UIImage sd_imageWithData:self.imageData]; //增長的代碼 NSData *data = UIImageJPEGRepresentation(image, 1); self.imageData = [NSMutableData dataWithData:data]; // NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; image = [self scaledImageForKey:key image:image]; // Do not force decoding animated GIFs if (!image.images) { if (self.shouldDecompressImages) { 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); } } else { completionBlock(nil, nil, [NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}], YES); } } self.completionBlock = nil; [self done]; }
四、在控制器的- (void)didReceiveMemoryWarning方法中添加oop
[[SDWebImageManager sharedManager] cancelAll]; [[SDImageCache sharedImageCache] clearMemory];
第二種:新版本post
解壓縮意義:
當完成圖片加載或者從本地加載圖片時,還會有輕微的卡頓。由於當顯示或者繪製的時候,UIKit 只作了額外的延遲初始化和消耗很高解碼。因此從後臺線程解壓縮成合適的格式,從而讓系統沒必要作額外的轉換。而後在主線程上顯示,增長流暢性。
優化爲什麼拔苗助長?最後在SDWebImage的issues找到了相關的討論:
https://github.com/rs/SDWebImage/issues/538
其中一個harishkashyap大神是這麼回答的:
harishkashyap commented on Dec 23, 2014
Its the memory issue again. decodedImageWithImage takes up huge memory and causes the app to crash. I have added an option to put this off in the library but defaulting to YES so there aren't any breaking changes. If you put off the decodeImageWithImage method in both image cache and image downloader then you shouldn't be seeing the VM: CG Raster data on the top consuming lots of memory
decodeImageWithImage is supposed to decompress images and cache them so the loading on tableviews/collectionviews become better. However, with large set of images being loaded, the experience worsened and the memory of uncompressed images even with thumbnails can consume GBs of memory. Putting this off only improved performance.
這位大神提到,decodeImageWithImage這個方法用於對圖片進行解壓縮而且緩存起來,以保證tableviews/collectionviews 交互更加流暢,可是若是是加載高分辨率圖片的話,會拔苗助長,有可能形成上G的內存消耗。該大神建議,對於高分辨率的圖片,應該在圖片解壓縮後,禁止緩存解壓縮後的數據,相關的代碼處理爲:
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO]; [[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
固然,你也能夠設置SDWebImage的其餘參數,好比是否緩存到內存以及內存緩存最高限制等,來保證內存安全:
shouldCacheImagesInMemory 是否緩存到內存 maxMemoryCost 內存緩存最高限制
號外:蘋果官方給出了一個下載高清大圖的demo,內存消耗很低。感興趣的朋友也能夠看看:
https://developer.apple.com/library/ios/samplecode/LargeImageDownsizing/Introduction/Intro.html
bitsPerComponent 表示存入內存中的每一個像素中的每個組件所佔的位數; bytesPerRow 表示存入內存中的位圖的每一行所佔的字節數;