面试题答案
一键面试内存管理
- 自动释放池优化:
- 在频繁创建临时对象的循环中,手动创建自动释放池。例如,如果有一个循环会创建大量的
NSString
临时对象:
for (int i = 0; i < 1000; i++) { @autoreleasepool { NSString *tempString = [NSString stringWithFormat:@"%d", i]; // 对tempString进行操作 } }
- 这样在每次循环结束时,自动释放池内的对象会被释放,避免了大量对象堆积在默认自动释放池中导致的内存峰值。
- 在频繁创建临时对象的循环中,手动创建自动释放池。例如,如果有一个循环会创建大量的
- 对象生命周期管理:
- 及时释放不再使用的对象。比如在视图控制器的
dealloc
方法中,释放视图控制器持有的资源,如self.someLargeDataArray = nil;
,以确保对象被销毁时,其占用的内存能被系统回收。 - 使用弱引用(
weak
)避免循环引用。例如在一个视图控制器ViewController
和它内部的一个自定义视图CustomView
中,如果CustomView
持有对ViewController
的引用,将这个引用声明为weak
,防止循环引用导致内存泄漏:
@interface CustomView : UIView @property (nonatomic, weak) ViewController *viewController; @end
- 及时释放不再使用的对象。比如在视图控制器的
- 缓存复用:
- 对于频繁创建且占用资源较大的对象,可以使用缓存机制。例如,在一个绘图应用中,经常需要创建
NSBezierPath
对象来绘制图形,可以创建一个NSMutableDictionary
作为缓存,根据特定的标识(如图形类型)来复用已经创建的NSBezierPath
对象。
static NSMutableDictionary *pathCache; + (NSBezierPath *)cachedPathForType:(NSString *)type { if (!pathCache) { pathCache = [NSMutableDictionary dictionary]; } NSBezierPath *path = pathCache[type]; if (!path) { path = [NSBezierPath new]; // 配置path pathCache[type] = path; } return path; }
- 对于频繁创建且占用资源较大的对象,可以使用缓存机制。例如,在一个绘图应用中,经常需要创建
线程调度
- GCD(Grand Central Dispatch)优化:
- 使用合适的队列:对于一些不影响主线程UI的任务,如数据处理、文件读写等,使用全局队列。例如,在后台下载文件:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(globalQueue, ^{ NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://example.com/file"]]; // 处理下载的数据 });
- 控制并发度:如果有多个任务需要并发执行,但又要避免过度占用资源,可以使用信号量来控制并发度。比如有10个任务,但只想同时执行3个:
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(3); for (int i = 0; i < 10; i++) { dispatch_async(concurrentQueue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 执行任务 dispatch_semaphore_signal(semaphore); }); }
- NSOperationQueue优化:
- 设置操作优先级:根据任务的重要性和紧急程度设置
NSOperation
的优先级。例如,在一个地图应用中,地图数据的加载操作优先级高于一些次要信息的加载:
NSOperationQueue *operationQueue = [NSOperationQueue new]; NSBlockOperation *mapDataOperation = [NSBlockOperation blockOperationWithBlock:^{ // 加载地图数据 }]; mapDataOperation.queuePriority = NSOperationQueuePriorityHigh; NSBlockOperation *secondaryInfoOperation = [NSBlockOperation blockOperationWithBlock:^{ // 加载次要信息 }]; secondaryInfoOperation.queuePriority = NSOperationQueuePriorityLow; [operationQueue addOperation:mapDataOperation]; [operationQueue addOperation:secondaryInfoOperation];
- 依赖关系管理:合理设置操作之间的依赖关系,确保任务按正确顺序执行。例如,一个数据解析操作依赖于数据下载操作完成:
NSBlockOperation *downloadOperation = [NSBlockOperation blockOperationWithBlock:^{ // 下载数据 }]; NSBlockOperation *parseOperation = [NSBlockOperation blockOperationWithBlock:^{ // 解析数据 }]; [parseOperation addDependency:downloadOperation]; NSOperationQueue *operationQueue = [NSOperationQueue new]; [operationQueue addOperation:downloadOperation]; [operationQueue addOperation:parseOperation];
- 设置操作优先级:根据任务的重要性和紧急程度设置
网络请求(如果涉及)
- 优化请求频率:
- 合并请求:如果有多个小的网络请求获取相关数据,可以合并为一个请求。例如,在一个用户信息展示界面,原本需要分别请求用户基本信息、用户设置信息和用户最近活动信息,可以将这些数据的获取合并到一个API接口中,减少网络请求次数。
- 缓存策略:对于不经常变化的数据,使用本地缓存。可以使用
NSURLCache
设置缓存策略。例如,对于一些静态配置文件的请求:
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:@"myCache"]; [NSURLCache setSharedURLCache:sharedCache]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com/config"]]; request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 处理数据 }]; [task resume];
- 优化请求内容:
- 减少数据传输量:在请求和响应中,只传输必要的数据。例如,在请求用户信息时,只请求展示界面需要的字段,而不是获取整个用户数据对象。
- 压缩数据:服务器端对响应数据进行压缩,客户端在接收数据时解压缩。可以使用
NSURLSession
的NSURLSessionConfiguration
来支持压缩,configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
,这样服务器可以根据自身配置对数据进行压缩(如使用gzip压缩),客户端在接收时自动处理解压。