自动释放池
- 在 mrc 的代码中,没有 weak,只有 assign
- assign 修饰符号,对对象不做任何操作,只是简单的记录地址
- weak 是 ARC 专有的,如果对象没有其他任何对象做强引用,会被立即释放!
- weak 的效率非常差!
- assign 会记录住地址,对象释放后,地址仍然保留,在 MRC 开发中,野指针错误非常频繁
-
weak 安全性很好!一旦没有强引用,自动将地址设置为 nil,OC中可以向 nil 发送任何消息都不会抱错!
-
autorelease 作用就是
延迟释放
,给对象添加延迟释放的标记自动释放对象 atuorelease
自动释放对象
- 所有 "autorelease" 的对象,在出了作用域之后,会被自动添加到"最近创建的"自动释放池中!
- 在自动释放池被销毁或者耗尽的时候,会向池中所有对象发送 release 消息,释放池中对象
- 自动释放池,在 ARC & MRC 程序中,同样有效!
MRC 下系统变量的测试
声明变量
@property (nonatomic, assign) UIButton *btn;
向控制器View中添加按钮:
// alloc / init - 应该出了作用域才会被释放 // self.btn = [[UIButton alloc] init]; self.btn.frame = CGRectMake(40, 40, 100, 100); self.btn.backgroundColor = [UIColor orangeColor]; [self.view addSubview:self.btn]; NSLog(@"%@", self.view.subviews); // 类方法创建的 - 是 ‘autorelease’ 的 // 出了作用域,会被添加到自动释放池中 // 自动释放池被销毁前,才释放对象! self.btn = [UIButton buttonWithType:UIButtonTypeContactAdd]; [self.view addSubview:self.btn]; NSLog(@"%@", self.view.subviews); // ARC 上述演练不好使!以 weak 为主!
运行结果:
2015-03-25 10:31:20.055 09-自动释放池[27279:718327] ( "<_UILayoutGuide: 0x7fc5d0d346b0; frame = (0 0; 0 0); hidden = YES; layer = >", "<_UILayoutGuide: 0x7fc5d0e77950; frame = (0 0; 0 0); hidden = YES; layer = >", ">" ) 2015-03-25 10:31:20.063 09-自动释放池[27279:718327] ( "<_UILayoutGuide: 0x7fc5d0d346b0; frame = (0 0; 0 0); hidden = YES; layer = >", "<_UILayoutGuide: 0x7fc5d0e77950; frame = (0 0; 0 0); hidden = YES; layer = >", ">", ">" )
可以看到,无论是alloc还是buttonWithType: 都是可以添加到控制器的View上的,也就意味着,创建出来的button并没有立刻销毁
- assign 声明的变量,在alloc后,对象并不会立刻释放,除了作用域才会销毁,即使是对象销毁后,assign记录的地址并不会清除,这就很容易造成
野指针
错误 - 利用buttonWithType: 创建出来的,也不会立刻释放,系统类方法创建出来的对象,是默认
autorealease
的,出了作用域,会自定添加到自动释放池
中,自动释放池销毁前,才会释放对象,同样assign声明的变量会持有该对象的地址,一直不肯放~MRC下自定义对象的自动释放
Person.h
@interface Person : NSObject + (instancetype)person; @end
Person.m
- 注意:这里没有添加autorelease
@implementation Person + (instancetype)person { // autorelease 作用就是延迟释放 // 给对象添加延迟释放的标记 Person *p = [[Person alloc] init] ; return p; } - (void)dealloc { NSLog(@"我去了"); [super dealloc]; } @end
声明Persion变量:
@property (nonatomic, assign) Person *p;
测试Demo:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.p = [Person person]; NSLog(@"%@", self.p); }
运行结果:
2015-03-25 10:44:16.652 10-ARC自动释放[27546:726446]
小结:
在MRC下,如果提供的类方法没有autorelease,那么在调用的时候,用assign变量接收,仍然会打印出对象的地址,当然对象并没有销毁(
dealloc没有输出
)。将类方法带上 autorelease
Person *p = [[[Person alloc] init] autorelease];
打印结果:
2015-03-25 10:56:04.224 10-ARC自动释放[27690:732059] 2015-03-25 10:56:04.238 10-ARC自动释放[27690:732059] 我去了
可以看到对象被释放了,说明autorelease给对象添加了
延迟释放
的标记,让对象在自动是释放池销毁,或者出了离它最近的自动释放池作用域的时候,自动释放。ARC中的自动释放
变量的声明:
@property (nonatomic, weak) Person *p; @property (nonatomic, weak) UIButton *button;
测试Demo:
// ARC 中,如果给 weak 做 alloc / init 的设置数值,Xcode 会提示! self.p = [[Person alloc] init]; // 对于 Xcode 编译器而言,只要是类方法,就不会提示! // 如果使用 MRC 开发,所有 返回 instancetype 的类方法,返回的对象都是 autorelease 的! // 因为没有强引用,会被立即释放 self.p = [Person person]; // ARC中之所以为 null,是因为 weak,跟autorelease没有关系! NSLog(@"%@", self.p); // 之所以会这样是因为苹果框架的底层是用 MRC 写的,buttonWithType返回的对象是带有 autorelease self.button = [UIButton buttonWithType:UIButtonTypeContactAdd]; NSLog(@"%@", self.button);
打印结果:
2015-03-25 11:00:58.756 10-ARC自动释放[27778:735123] (null) 2015-03-25 11:00:58.769 10-ARC自动释放[27778:735123] >
小结
- 如果普通对象的alloc,且对象是weak的,Xcode会自动提示警告,告诉你这个对象,一创建就会被销毁啦
- 但是如果你提供了一个类方法,快速生成。即使内部写的是alloc,Xcode也不会警告你,但是你不能改变一创建就被销毁的事实。
- 苹果自己提供的类方法创建的button,我们用weak接收,却没有销毁,为啥呢,因为苹果框架的底层是用MRC写的,buttoWithType:返回的对象都是带
autorelease
的,意味着会延迟销毁,仅仅是被添加到自动释放池而已,等待着出自动释放池作用域或者自动释放池销毁。而不会立刻销毁。
- 注意:这里没有添加autorelease
- assign 声明的变量,在alloc后,对象并不会立刻释放,除了作用域才会销毁,即使是对象销毁后,assign记录的地址并不会清除,这就很容易造成