1.__Strong ARC 无效时,引用计数器加1,当超出作用域,引用为nil,由于未执行release 方法,对象还存在堆中,而此时引用销毁了,对象没有销毁,出现内存泄漏
ARC 有效时,引用计数器加1,当超出作用域,当系统判断引用为nil时,系统自动销毁对象。
ARC 情况下
2.__Weak ARC 不持有对象,自动加入自动释放池autorelaesepool;
(1.)不持有对象,
例如 id __weak obj = [[ NSObject alloc ]init];系统警告,发现是以__weak 修饰的引用obj 系统会在创建好对象后,自动release掉。
(2.)自动加入自动释放池
例如 id __strong obj = [[ NSObject alloc ]init];
id __weak obj1=obj;{
伪代码如下:id__weak obj1 = obj,
id _autoreleasing tmp = obj1; (加入自动释放池)
}
obj超出作用域,引用为nil,同时obj1引用为nil,(对象是否销毁要看系统什么时候销毁自动释放池,此时只是两个引用为nil)自动释放池此时持有对象,自动释放池销毁时销毁对象(系统在合适的时机销毁自动释放池)这个合适的时机就是当前的RunLoop循环结束。
3.__autorelease 将对象放入自动释放池,系统在合适的时机销毁自动释放池,同时销毁池内的对象。
4.__unsafe_unretained 不安全的所有权修饰符,如果用__unsafe_unretained 修饰的引用指向对象系统报错,同__weak, 例如 id __unsafe_unretained obj = [[ NSObject alloc ]init];系统 警告,
例如 id __strong obj = [[ NSObject alloc ]init];
id __unsafe_unretained obj1=obj;
obj 赋值给obj1,既不持有对象的强引用,也不持有对象的弱引用,当obj 超出作用域时,引用对象销毁,obj为nil,obj1为野指针。
ARC
1.__strong 的具体实现
id obj(默认strong)= [[ NSObject alloc ]init];
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
当超出obj 的作用域时自动销毁
2.__weak 的具体实现
id obj(默认strong)= [[ NSObject alloc ]init];
赋值为nil
id __weak obj1 = obj
obj1 = 0;
objc_storeWeak(&obj1,obj)
objc_storeWeak(&obj1,o)
(把第二参数的地址作为键值,将对参数的附有__weak 修饰符的变量注册到weak 表中,如果第二参数为0,记obj超出作用域或者obj为nil 则把变量地址从weak 表中删除,将obj1赋值为nil)
注册到自动释放池
objc_initWeak (&obj1,obj);
id temp = objc_loadWeakRetained(&obj1) (引用计数加1)
objc_autorelease(temp);
系统发现用__weak 修饰时通过 objc_loadWeakRetained 函数取出__weak 修饰符变量所引用的对象retain,然后放入自动释放池,objc引用超出作用域,指针销毁,obj1销毁,对象等自动释放池释放时销毁。
5copy
copy 分为三种情况
1.当修饰,NSMutableString NSMutableArry 等可变的字符串或者数组时,必须用copy,因为strong 是单纯增加对象的引用计数,改变的同时会同时改变源对象,而copy 是做的深拷贝,改变对象的同时,对源对象没有影响,所以必须用copy。
2.当修饰不可变字符串或者数组,字典时分为两种情况
1.当传入的对象也为不可变对象时,用copy和strong 没有区别,例如
1.
NSString *textStr = @“TextString”;
self.StrStrong = textStr;
self.strCopy =textStr;
当textStr 的值改变时,self.StrStrong或者self.StrStrong 的值并不会因为textStr的值改变而发生改变,因为不可变字符串在代码区,例如当textStr = @“TextString” 时,textStr 指向的是TextString 的首地址,而当textStr = @“TextString1”,textStr 指向的是TextString1 的首地址
记当textStr = @“TextString”;self.StrStrong = textStr;self.StrStrong = strCopy;时,他们三个的地址都是指向“TextString”的首地址,当self.StrStrong = @"TextChange" 时,textStr和self.strCopy还是指向TextString,所以他们三个当中任意一个的值改变都不会影响到对方,所以用Strong和copy 没有任何区别.
2.
NSMutableString *textStr = [NSMutableString stringWithString:@"textStr"];
self.StrStrong = textStr;(指向的是对象textStr,强引用,引用计数器加1)
self.strCopy= textStr;(对对象textStr 的一次深拷贝)
当textStr 的值改变时,self.StrStrong 的值会发生改变因为self.StrStrong和textStr指向的是同一个对象,而self.strCopy对textStr做的是深拷贝,所以值不会发生改变。所以在进行赋值操作时如果接收的对象是可变对象,也必须用copy。
注意:因为在进行赋值操作时,我们并不能确定传递的是可变字符串、字典、数组,还是不可变字符串、字典、数组。所以我们应该统一用copy 这样就可以避免出现对象改变的情况,bug出现的几率会大大降低,所以建议不管是可变不可变时都统一用copy