面试题答案
一键面试内存管理策略
- 自动释放池
- 在频繁创建临时对象的代码块中,手动创建自动释放池。例如在循环中创建大量临时对象时:
@autoreleasepool { for (int i = 0; i < 1000; i++) { NSString *tempString = [NSString stringWithFormat:@"%d", i]; // 对tempString进行操作 } }
- 这样在自动释放池结束时,其中的对象会被自动释放,避免内存峰值过高。
- 对象生命周期管理
- 确保对象在不再使用时及时释放。对于视图控制器等对象,在
dealloc
方法中释放相关资源,比如取消网络请求、移除通知监听等:
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; if (self.networkTask) { [self.networkTask cancel]; self.networkTask = nil; } }
- 使用
weak
和unowned
(在ARC环境下)来避免循环引用。例如在视图控制器和其代理之间,代理属性通常声明为weak
:
@interface MyViewController : UIViewController <MyDelegate> @property (nonatomic, weak) id<MyDelegate> delegate; @end
- 确保对象在不再使用时及时释放。对于视图控制器等对象,在
- 缓存机制
- 对于一些频繁使用且创建开销较大的对象,如图片、字体等,使用缓存。可以使用
NSCache
来缓存对象,NSCache
会自动根据系统内存情况释放缓存对象:
static NSCache *imageCache; + (void)initialize { if (self == [MyClass class]) { imageCache = [[NSCache alloc] init]; } } - (UIImage *)cachedImageForKey:(NSString *)key { return [imageCache objectForKey:key]; } - (void)cacheImage:(UIImage *)image forKey:(NSString *)key { [imageCache setObject:image forKey:key]; }
- 对于一些频繁使用且创建开销较大的对象,如图片、字体等,使用缓存。可以使用
性能优化思路与经验
代码架构方面
- 模块化设计
- 将功能拆分成独立的模块,每个模块负责单一的功能。例如将数据获取、数据处理、视图展示分别封装成不同的模块。这样可以提高代码的可维护性和可复用性,也便于对每个模块进行单独的性能优化。
- 以数据获取模块为例,可以封装成一个
APIManager
类,集中管理网络请求,并且可以在这个类中进行缓存处理等优化。
- 避免过度继承
- 过多的继承层次可能导致代码复杂度增加,影响性能。尽量使用组合而不是继承来实现功能复用。例如,如果一个视图需要具备某种特定的行为,可以将该行为封装成一个独立的类,然后在视图类中组合使用这个类,而不是通过继承来获取该行为。
- 懒加载
- 对于一些非必要立即创建的对象,使用懒加载。例如视图控制器中的子视图:
- (UILabel *)myLabel { if (!_myLabel) { _myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50)]; _myLabel.text = @"Hello"; } return _myLabel; }
- 这样只有在真正需要使用该对象时才会创建,减少了初始化时的性能开销。
资源加载方面
- 图片加载优化
- 对于图片,根据不同的设备分辨率加载合适尺寸的图片。可以在
Assets.xcassets
中添加不同分辨率的图片,系统会自动根据设备选择合适的图片加载。 - 使用渐进式加载图片的方式,尤其是在网络加载图片时。可以先加载低分辨率的图片快速显示,然后再加载高分辨率的图片替换。
- 对于静态图片,可以将其转换为
webp
格式(如果支持),webp
格式通常比png
或jpg
有更好的压缩率,能减少图片的下载和加载时间。
- 对于图片,根据不同的设备分辨率加载合适尺寸的图片。可以在
- 数据加载优化
- 在网络数据加载时,尽量使用缓存机制。可以在本地缓存数据,当再次请求相同数据时,先从本地缓存读取,若缓存过期或不存在,再从网络获取。可以使用
NSURLCache
来实现简单的网络缓存。 - 对于大数据量的加载,采用分页加载的方式,避免一次性加载大量数据导致内存占用过高和性能下降。例如在加载列表数据时,每次只加载一页的数据。
- 优化网络请求,合并多个小的网络请求为一个大的请求,减少网络请求次数,降低网络开销。同时,合理设置网络请求的超时时间,避免过长的等待时间。
- 在网络数据加载时,尽量使用缓存机制。可以在本地缓存数据,当再次请求相同数据时,先从本地缓存读取,若缓存过期或不存在,再从网络获取。可以使用