iOS-@property-所有权修饰符
自己生成的对象,自己所持有;
非自己生成的对象,自己也能持有;
自己持有的对象不再需要时释放;
非自己持有的对象无法释放;
所有权修饰符:
OC将变量类型定义为id类型或各种对象类型;类型上必须附加所有权修饰符。
所有权修饰符共有四种:
strong修饰符; weak修饰符;
unsafe_unretained修饰符; autoreleasing修饰符;
strong修饰符: strong修饰符是id类型和对象类型默认的所有权修饰符。
strong修饰符表示对对象的“强引用”。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。 strong修饰符的变量,不仅仅只在变量作用域中,在赋值上也能够正确的管理对象的所有者。
通过废弃带__strong修饰符的变量(变量作用域结束或者成员变量所属对象废弃)或者对变量赋值,都可以做到“不再需要自己持有对象时释放”。
weak修饰符: strong修饰符虽然已经能解决大部分内存管理的问题,但是有些重大问题还是不能解决,比如循环引用的问题。
循环引用容易引发内存泄漏的问题。
循环引用包括,对象之间互相引用,以及对象对自身的引用。
weak修饰符可以避免循环引用。weak修饰符提供弱引用,弱引用不能持有对象实例。
在持有某个对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil状态。
weak修饰符只能用于iOS5以上及OS X Lion以上版本的应用程序。
iOS4以及OS X Snow Leopard的应用程序中可使用
unsafe_unretained修饰符来代替。
unsafe_unretained修饰符: unsafe_unretained修饰符和weak修饰符在使用上是一样的。
但是在使用
unsafe_unretained修饰符赋值给附有strong修饰符的变量时,有必要确保被赋值的对象确实存在。
这种修饰符存在的原因就是因为在iOS4以及OS X Snow Leopard的应用程序中,需要使用其来代替
weak修饰符。赋值给附有__unsafe_unretained修饰符变量的对象在通过该变量使用时,如果没有确保其确实存在,那么应用程序可能就会崩溃。
__autoreleasing修饰符:
后续再加
strong:强引用。ARC中不再使用retain,使用strong替代,因此strong和retain同义,可使对象的引用数加1;
weak:弱引用。不持有对象,不会对对象的引用计数加1;当对象被释放后,会指向nil,不会产生野指针;一般在可能出现循环引用的情况下是呀,如delegate。
assign:修饰非对象类型和基础数据类型的属性,不涉及内存管理,因此也不会被引用计数。
copy:创建一个新的对象,新对象的引用计数+1,但不会改变原来的对象的引用计数。
nonatomic:和atomic相对,是非原子性操作,非线程安全;
atomic:原子性操作,线程安全,但是会影响性能;
readwrite:可读可写,getter/setter
readonly:可读不可写,getter
writeonly:可写不可读,setter
NSString为什么要用copy修饰,而不是strong?
copy和strong修饰的区别,其实只在传入NSMutableString的表现上有所区别。下面举例来说明,代码如下:
NSString *strTest = [NSString stringWithFormat:@"hello!"];
self.strStrong= strTest;
self.strCopy= strTest;
NSLog(@"strTest = %@, content = %p, address = %p", strTest, strTest, &strTest);
NSLog(@"self.strStrong = %@ content = %p, address = %p", _strStrong, _strStrong, &_strStrong);
NSLog(@"self.strCopy = %@ content = %p, address = %p", _strCopy, _strCopy, &_strCopy);
NSMutableString *mutabllStrTest = [NSMutableString stringWithFormat:@"How are you?"];
self.strStrong= mutabllStrTest;
self.strCopy= mutabllStrTest;
NSLog(@"mutabllStrTest = %@, content = %p, address = %p", mutabllStrTest, mutabllStrTest, &mutabllStrTest);
NSLog(@"self.strStrong = %@, content = %p, address = %p", _strStrong, _strStrong, &_strStrong);
NSLog(@"self.strCopy = %@, content = %p, address = %p", _strCopy, _strCopy, &_strCopy);
[mutabllStrTestappendString:@" I'm fine."];
NSLog(@"---------------------------------------");
NSLog(@"mutabllStrTest = %@, content = %p, address = %p", mutabllStrTest, mutabllStrTest, &mutabllStrTest);
NSLog(@"self.strStrong = %@, content = %p, address = %p", _strStrong, _strStrong, &_strStrong);
NSLog(@"self.strCopy = %@, content = %p, address = %p", _strCopy, _strCopy, &_strCopy);
首先分别声明strong和copy修复的变量;
然后我们将NSString类型的字符串赋给这两个变量:
根据打印的字符串内容和内存地址,可以看出: strStrong和 strCopy都指向NSString的 strTest地址,并且指向的内容也是相同的。也就是说, strStrong和 strCopy对strTest都做了浅拷贝,只拷贝了其指向的内容。
而当我们将 NSMutableString类型的字符串复制给这两个变量时:
根据打印的字符串内容和内存地址,可以看出:strStrong仍然指向的是 mutabllStrTest的地址,而strCopy则是对mutabllStrTest做了一次深拷贝,也就是对strCopy指向了一个新生成的对象,这个对象的内容和mutabllStrTest暂且保持一致。这个strCopy新生成的对象不会使mutabllStrTest的引用计数发生变化。
而当我们对NSMutableString类型的mutabllStrTest做了一些变化时,可以发现:strStrong跟随mutabllStrTest做了变化,而strCopy依然是如复制初时的样子。
因此,当传入的字符串为NSString类型时,copy和strong的效果是一致的。但是如果是NSMutableString类型,就要注意copy和strong的修饰符了。