内容针对ARC版本而言 如有遗漏和错误 还望指正
属性的使用场景
一般而言
delegate、UI控件用weak
block、NSString用copy
基本数据类型int\float\BOOL\枚举\结构体 id 用assign
上述对象外用strong
属性的介绍
assign与weak
assign与weak都是简单赋值,不更改索引计数。
assign看起来跟weak一样,其实不能混用的,assign的变量在释放后并不设置为nil(和weak不同),当你再去引用时候就会发生错误。
两个的差别在于,weak用于对象类型,就是指针类型,而assign用于简单的数据类型,如int BOOL 等。
基本数据类型不属于对象,它的创建和使用都是在栈中,超出对应方法体即被清除,所以不需要使用垃圾处理机制,无需记录索引值,所以使用assgin。
assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针!
对应__weak
关键字,与assign
相对应.weak
用在arc
下,assign
用在mrc
情况下用,weak
比assign
多了一个在内存被销毁的情况下自动nil,防止野指针出现.
UI控件之所以可以用弱指针 是因为控制器有强指针指向self.view
, self.view
有强指针指向subviews数组 数组中有强指针指向控件,代理必须是weak 因为代理一般都指向控制器 会造成循环引用 造成内存泄露.
strong
对应__strong
关键字,即该属性所声明的变量将成为对象的持有者.与retain相对应,使用了引用计数,retain+1,release -1;当引用 计数为0时,dealloc会被调用,内存被释放
copy
对应__strong
关键字,建立一个索引计数为1的对象,然后释放旧的对象.用于非共享内存时,每个指针有自己的内存空间.与strong 的区别是声明变量是拷贝对象的持有者.
用copy的属性set 方法不能直接赋值要用 _xx = [xx copy]
atomic(默认)
线程安全型,在多线程中只能有一个线程能对它进行访问,非ARC编译环境下,需要设置访问锁来保证对该变量进行正确的get/set,防止在写未完成的时候被另外一个线程读取,造成数据错误。
nonatomic
非原子性访问
非线程安全型,多个线程可以同时对其进行访问,当两个不同的线程对其访问时,容易失控.
总结:atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:
<code>
if (property != newValue) {
[property release];
property = [newValue retain];
}
</code>
readonly
只有get方法,没有set方法.
readwrite
默认属性,有get/set方法.
unsafe_unretauined
对应关键字__unsafe_unretained
,声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了.所以很少使用用在ARC编译环境下,与assign相似.用于iOS 5之前的系统
__block
在block内部访问并修改外部变量时 外部变量需要用__block修饰
只是引用的话不需要
属性的使用场景
@interface ViewController : UIViewController
{
//成员变量
NSArray *array1;
}
//属性变量
@property (nonatomic,strong) NSArray *array2;
@end
-(void)viewDidLoad
{
[super viewDidLoad];
array1 = [[NSArray alloc] initWithObjects:@"abcde", nil];
array2 = [[NSArray alloc] initWithObjects:@"123abc", nil];
{
// 局部变量
NSArray *array1 = [[NSArray alloc] initWithObjects:@"12345", nil];
}
NSLog(@"\narray1 : %@\n array2 : %@",array1,array2);
}
局部变量是根据其生存周期定义的,在源文件中的array1,其生命周期是在以“{ }”为界限的代码块中,虽然它的名称与成员变量相同,但不是同一个变量。成员变量是用于一个区域内的临时变量。
成员变量,本例中的是实例成员变量,是作用于整个类对象内的。从生命周期来看,它比局部变量要长一些,但它默认是私有的,其他对象是无法访问到的。因此,一般自定义方法,作为一个接口让其他对象访问这个变量。因此,成员变量用于类内部,无需与外界接触的变量。
封装
如果成员变量是private,程序中的其它对象很难直接访问该成员变量。如果是属性,相对更容易用父类方法读写属性。
性能
成员变量地址可以根据实例的内存地址偏移寻址。而属性的读写都需要函数调用,相对更慢。
非基础类型
对于复杂的C++类型,往往设为成员变量更合适,也许这种类型不支持copy,或者完全复制很麻烦。
多线程
多线程环境下,为保证数据一致性,在需要同步执行的代码段更应该使用成员变量。如果对需要同步更新的数据用getter/setter 方法,数据更新效率低,会带来更多的获取锁请求失败。
程序正确性
成员变量可以做直观的内存管理。属性可以一层层继承,还可以复写。容易出错。
二进制文件的体积
默认用属性,会生成不必要的getter/setter 方法,程序体积会变大。
根据成员变量的私有性,为了方便访问,所以就有了属性变量。属性变量的好处就是允许让其他对象访问到该变量。当然,你可以设置只读或者可写等,设置方法也可自定义。所以,属性变量是用于与其他对象交互的变量。
后记:
没写属性的变量的默认 都是strong 缺省关键字就是__strong
在用到block时的__block和__weak
__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型修饰对象可以在block中被重新赋值。
__weak只能在ARC模式下使用,也只能修饰对象,不能修饰基本数据类型被修饰过的也并不可以重新赋值,目前见到和block一起用的最多的就是防止循环引用.__weak typeof(self) share = self
关键字__autoreleasing
__autoreleasing 都是用来修饰变量的.
__autoreleasing 如用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放.
在MRC下,使用autorelease让某个对象延迟释放
-(ClassA *)TestMethod{ ClassA *classA = [[ClassA alloc] init]; return [classA autorelease];}
在ARC下,需要使用如下方式替代:
-(ClassA *)TestMethod{ __autoreleasing ClassA *classA = [ClassA alloc] init]; return classA;}
或:
-(NSString *)TestMethod:(_autoreleasing ClassA *)classA{ classA = [[ClassA alloc] init]; return classA;}
strong 和copy
https://www.mgenware.com/blog/?p=2121
http://blog.csdn.net/liushuo19920327/article/details/51465318
http://www.cnblogs.com/csj007523/archive/2012/07/23/2605662.html
http://www.cnblogs.com/langtianya/p/3722129.html