面试题答案
一键面试图片预处理
- 格式转换:
- 将图片格式统一转换为更适合iOS设备显示且占用空间较小的格式,如
WebP
(虽然iOS原生不支持,但可通过引入第三方库支持,如libwebp
)。若使用原生支持的格式,优先选择JPEG
(适合色彩丰富的照片)和PNG
(适合简单图形和透明度要求高的图片)。在开发过程中,可通过脚本在构建前对图片资源进行格式转换。 - 使用工具(如
ImageOptim
)对图片进行无损压缩,去除图片中不必要的元数据等,进一步减小图片文件大小。
- 将图片格式统一转换为更适合iOS设备显示且占用空间较小的格式,如
- 尺寸调整:
- 根据不同设备的屏幕分辨率和图片展示区域的大小,提前对图片进行裁剪和缩放处理。在
Assets.xcassets
中,为不同屏幕尺寸提供合适分辨率的图片,如@1x
、@2x
、@3x
等,确保应用在不同设备上加载合适尺寸的图片,避免加载过大图片造成内存浪费。 - 若图片展示区域大小不固定,在加载图片前根据实际展示区域的大小计算合适的尺寸,然后使用
UIGraphicsBeginImageContextWithOptions
等方法对图片进行缩放。例如:
UIImage *originalImage = [UIImage imageNamed:@"bigImage"]; CGFloat targetWidth = 100; CGFloat targetHeight = originalImage.size.height * (targetWidth / originalImage.size.width); UIGraphicsBeginImageContextWithOptions(CGSizeMake(targetWidth, targetHeight), NO, 0.0); [originalImage drawInRect:CGRectMake(0, 0, targetWidth, targetHeight)]; UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
- 根据不同设备的屏幕分辨率和图片展示区域的大小,提前对图片进行裁剪和缩放处理。在
加载流程优化
- 异步加载:
- 使用
NSOperationQueue
或GCD
(Grand Central Dispatch)来异步加载图片,避免阻塞主线程,确保应用的流畅性。例如,使用GCD
:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; UIImage *image = [UIImage imageWithData:imageData]; dispatch_async(dispatch_get_main_queue(), ^{ // 在主线程更新UI,如设置图片到UIImageView self.imageView.image = image; }); });
- 使用
- 渐进式加载:
- 对于较大的图片,实现渐进式加载,让用户能尽快看到图片的大致轮廓,随着时间推移图片细节逐渐清晰。在iOS中,虽然原生没有直接的渐进式加载支持,但可通过一些第三方库(如
SDWebImage
)来实现。这些库会先加载图片的低分辨率版本供用户快速浏览,然后在后台继续加载完整分辨率的图片。
- 对于较大的图片,实现渐进式加载,让用户能尽快看到图片的大致轮廓,随着时间推移图片细节逐渐清晰。在iOS中,虽然原生没有直接的渐进式加载支持,但可通过一些第三方库(如
缓存策略
- 内存缓存:
- 使用
NSCache
来实现内存缓存,NSCache
是线程安全的,并且在系统内存紧张时会自动释放内存。例如:
@interface ImageLoader : NSObject @property (nonatomic, strong) NSCache *imageCache; @end @implementation ImageLoader - (instancetype)init { self = [super init]; if (self) { self.imageCache = [[NSCache alloc] init]; } return self; } - (UIImage *)loadImageFromCacheWithURL:(NSURL *)url { return [self.imageCache objectForKey:url]; } - (void)cacheImage:(UIImage *)image forURL:(NSURL *)url { [self.imageCache setObject:image forKey:url]; } @end
- 使用
- 磁盘缓存:
- 可使用第三方库(如
SDWebImage
或AFNetworking
的图片加载扩展)来实现磁盘缓存。以SDWebImage
为例,它会将下载的图片缓存到磁盘,下次加载相同图片时先从磁盘读取。配置SDWebImage
的磁盘缓存很简单,如:
[SDImageCache sharedImageCache].config.maxCacheSize = 1024 * 1024 * 100; // 设置最大缓存大小为100MB [SDImageCache sharedImageCache].config.maxCacheAge = 60 * 60 * 24 * 7; // 设置缓存有效期为7天
- 可使用第三方库(如
内存监控与管理
- 内存警告处理:
- 在
UIViewController
中重写didReceiveMemoryWarning
方法,当接收到内存警告时,释放一些不必要的图片缓存和资源。例如:
- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // 清除内存缓存 [[ImageLoader sharedLoader].imageCache removeAllObjects]; // 释放当前视图中不显示的图片资源 if (self.currentlyNotDisplayedImageView) { self.currentlyNotDisplayedImageView.image = nil; } }
- 在
- 自动释放池:
- 在加载大量图片的循环中,手动创建自动释放池,及时释放不再使用的对象。例如:
for (int i = 0; i < largeNumberOfImages; i++) { @autoreleasepool { NSData *imageData = [NSData dataWithContentsOfURL:imageURLs[i]]; UIImage *image = [UIImage imageWithData:imageData]; // 处理图片,如缓存或显示 } }
- 仪器工具使用:
- 使用
Instruments
工具中的Leaks
和Allocations
来监控内存使用情况。Leaks
可检测内存泄漏,Allocations
可查看对象的分配和释放情况,帮助找出内存占用过高的地方并进行优化。通过分析Instruments
的报告,调整代码以减少内存峰值和泄漏。
- 使用