对象生命周期管理
- 遵循内存管理原则:在ARC环境下,对象的创建、持有和释放由编译器自动处理。开发者应避免手动调用
retain
、release
和autorelease
方法。例如,创建一个对象时,编译器会自动管理其引用计数:
NSObject *obj = [[NSObject alloc] init];
// 此时obj的引用计数为1,当obj超出作用域时,编译器自动释放该对象
- 局部变量作用域:对象的生命周期通常与声明它的局部变量作用域相关。当局部变量超出作用域,对象的引用计数会相应减少,当引用计数降为0时,对象被释放。
循环引用解决方法
- 使用
weak
关键字:weak
修饰的变量不会增加对象的引用计数,主要用于解决视图控制器之间或视图之间的循环引用。例如在视图控制器中:
@interface ViewControllerA : UIViewController
@property (nonatomic, weak) ViewControllerB *vcB;
@end
@interface ViewControllerB : UIViewController
@property (nonatomic, weak) ViewControllerA *vcA;
@end
- 使用
__block
和weak
结合(在block中):在block中,如果block捕获了外部对象,可能会导致循环引用。可以通过__block
和weak
结合解决。
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
// 使用strongSelf访问对象属性等操作
}
});
避免过度的内存分配与释放
- 对象复用:例如在UITableView中,复用单元格可以避免频繁创建和释放单元格对象。
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
- 延迟加载:对于一些不急需使用的对象,采用延迟加载的方式,在需要时才创建,减少初始内存占用。
- (NSArray *)dataArray {
if (!_dataArray) {
_dataArray = [[NSArray alloc] initWithObjects:@"item1", @"item2", nil];
}
return _dataArray;
}
ARC机制底层实现原理
- 编译器转换:编译器在ARC下会在合适的位置自动插入
retain
、release
和autorelease
代码。例如:
NSObject *obj = [[NSObject alloc] init];
// 编译器转换后类似如下代码(简化示意)
NSObject *obj = objc_msgSend(NSObject.class, @selector(alloc));
obj = objc_msgSend(obj, @selector(init));
// 当obj超出作用域时,编译器插入释放代码
objc_msgSend(obj, @selector(release));
- 引用计数管理:每个对象都有一个与之关联的引用计数。当对象被创建时,引用计数初始化为1。每次
retain
操作会使引用计数加1,每次release
操作会使引用计数减1。当引用计数降为0时,对象的内存被释放。
- Autorelease Pool:ARC仍然使用自动释放池。编译器会在适当的位置插入创建和销毁自动释放池的代码。例如在一个方法开始和结束处可能会创建和销毁自动释放池,在自动释放池中的对象会在自动释放池销毁时发送
release
消息。