面试题答案
一键面试结合ARC避免内存泄漏
- 原理:ARC负责自动管理对象的内存,当对象的引用计数降为0时,ARC会自动释放对象占用的内存。在GCD中,只要确保任务块(block)对对象的引用在任务执行完毕后正确处理,就可以避免内存泄漏。
- 实现方式:
- 避免循环引用:在block中使用
__weak
关键字修饰可能导致循环引用的对象。例如,假设在一个视图控制器中有一个GCD任务块:
__weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (strongSelf) { // 在这里使用strongSelf处理任务,这样可以避免block对self的强引用导致循环引用 // 当block执行完毕,strongSelf的引用计数减1,不会造成self的循环引用 } });
- 正确处理局部对象:在GCD任务块中创建的局部对象,ARC会在任务块执行完毕,对象的作用域结束时自动释放它们,只要不存在不合理的强引用链,就不会发生内存泄漏。
- 避免循环引用:在block中使用
频繁创建和销毁大量对象的性能优化
- 原理:频繁创建和销毁对象会导致大量的内存分配和释放操作,这会增加系统开销,影响性能。优化的核心思想是减少不必要的对象创建和销毁,重用对象资源。
- 实现方式:
- 对象池:
- 原理:创建一个对象池,预先创建一定数量的对象并存储在池中。当需要使用对象时,从池中获取;使用完毕后,将对象放回池中,而不是销毁它。这样可以减少对象的创建和销毁次数。
- 实现示例:
在GCD任务中使用对象池:// 定义一个对象池类 @interface ObjectPool : NSObject - (id)dequeueObject; - (void)enqueueObject:(id)object; @end @implementation ObjectPool { NSMutableArray *_pool; } - (instancetype)init { self = [super init]; if (self) { _pool = [NSMutableArray array]; // 预先创建一些对象放入池中 for (int i = 0; i < 10; i++) { id object = [[YourObjectClass alloc] init]; [_pool addObject:object]; } } return self; } - (id)dequeueObject { if (_pool.count > 0) { id object = _pool.lastObject; [_pool removeLastObject]; return object; } return [[YourObjectClass alloc] init]; } - (void)enqueueObject:(id)object { [_pool addObject:object]; } @end
ObjectPool *pool = [[ObjectPool alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ id object = [pool dequeueObject]; // 使用object进行任务处理 [pool enqueueObject:object]; });
- 延迟初始化:
- 原理:只有在真正需要使用对象时才进行初始化,而不是在程序启动或任务开始时就创建所有可能用到的对象。这样可以避免在不需要对象时占用内存,提高程序的启动性能和内存使用效率。
- 实现示例:
在GCD任务中:@interface MyClass : NSObject @property (nonatomic, strong) ExpensiveObject *expensiveObject; - (void)doTask; @end @implementation MyClass - (void)doTask { if (!_expensiveObject) { _expensiveObject = [[ExpensiveObject alloc] init]; } // 使用_expensiveObject进行任务处理 } @end
MyClass *myObj = [[MyClass alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [myObj doTask]; });
- 对象池: