现在发现有些东西,即使当时懂了,用的时候有会很模糊,还是需要自己写下来,慢慢总结才行
这里不能用NSString类型来测试苹果对它进行过优化。下面大家主要看*obj
这个对象的地址,另外一个地址我暂时也不清楚是什么地址
Strong
强引用,对象的引用计数器值+1
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, strong) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:s2 = <TestObj:0x7f97a9c73740>;
内存:前:_s1: 0x7f97a9fa0118 *_s1: 0x7f97a9c73740; _s2: 0x7f97a9fa0120 *_s2: 0x7f97a9c73740
后:_s1: 0x7f97a9fa0118 *_s1: 0x0; _s2: 0x7f97a9fa0120 *_s2: 0x7f97a9c73740
可见,s1指向的地址中的内容已经不存在了,但是因为引用计数+1了所以该块内存不会被释放,可以继续访问
Assign
弱引用,对象的引用计数器值不变,用于基础类型(基础类型copy,基础类型没有引用计数的概念)
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, assign) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:crash 但是打印出了s2 = 0x7fb668419500 (这里有时候会crash,有时候不会,当这块地址被回收了,就会crash。因为s1和s2指向同一块地址,当s1被释放了,地址就极可能会被回收。)
内存:前:_s1: 0x7fb66871ca28 *_s1: 0x7fb668419500; _s2: 0x7fb66871ca30 *_s2: 0x7fb668419500
后:_s1: 0x7fb66871ca28 *_s1: 0x0; _s2: 0x7fb66871ca30 *_s2: 0x7fb668419500
可见,s1指向的地址已经被回收,所以s2找不到地址。
Weak
弱引用,如果持有对象被释放,该对象也自动释放
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, weak) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:s2 = nil;
内存:前:_s1: 0x7f968973a888 *_s1: 0x7f9689554460; _s2: 0x7f968973a890 *_s2: 0x7f9689554460
后:_s1: 0x7f968973a888 *_s1: 0x0; _s2: 0x7f968973a890 *_s2: 0x0
可见,s1的内存地址被回收,s2的指针也变成nil,不会再指向该地址
Copy
拷贝一份
//对象要实现NSCopy协议
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, copy) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:s2 = <TestObj:0x7fdaf1f54300>;
内存:前:_s1: 0x7fdaf1d935f8 *_s1: 0x7fdaf1f543e0; _s2: 0x7fdaf1d93600 *_s2: 0x7fdaf1f54300
后:_s1: 0x7fdaf1d935f8 *_s1: 0x0; _s2: 0x7fdaf1d93600 *_s2: 0x7fdaf1f54300
可见,s1、s2指针指向的地址是不同的因为copy了一份,内容相同,不是原来的地址了,所以s1= nil,不影响s2
Retain
释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为+1
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, retain) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:s2 = <TestObj:0x7fdaf1f54300>;
内存:前:_s1: 0x7ffb5872cc78 *_s1: 0x7ffb5875c1b0; _s2: 0x7ffb5872cc80 *_s2: 0x7ffb5875c1b0
后:_s1: 0x7ffb5872cc78 *_s1: 0x0; _s2: 0x7ffb5872cc80 *_s2: 0x7ffb5875c1b0
可见,s1、s2指针指向的地址是相同的,所以s1= nil,不影响s2。因为引用+1了,所以该内存地址不会被回收
** unsafe_unretained**
和assign类似,但是它适用于对象类型,当目标被摧毁时,属性值不会自动清空(unsafe)。这是和weak的区别
@property (nonatomic, strong) TestObj *s1;
@property (nonatomic, unsafe_unretained) TestObj *s2;
self.s1 = [[TestObj allow] init];
self.s2 = self.s1;
self.s1 = nil;
NSLog(@"s2 = %@",self.s2);
结果:crash;
内存:前:_s1: 0x7fd5dbf7f698 *_s1: 0x7fd5dbfa42f0; _s2: 0x7fd5dbf7f6a0 *_s2: 0x7fd5dbfa42f0
后:_s1: 0x7fd5dbf7f698 *_s1: 0x0; _s2: 0x7fd5dbf7f6a0 *_s2: 0x7fd5dbfa42f0
可见,s1、s2指针指向的地址是相同的,s1=nil,让该块地址被回收,当s2指向这个地址时,就会找不到