Objective-C 中类属性(修饰)
(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)
assign: 简单赋值,不更改引用计数;
适用于基本数据类型(例如NSInteger)和C数据类型(int,float,double,char,等)以及指针的弱引用
注:指针的弱引用,比如:delegate,在ARC模式中用weak比较好,在非ARC模式中用assign
一、非ARC模式
copy: 建立一个索引计数为1的对象,然后释放旧的对象
retain: 释放旧的对象,将旧的对象的值赋予输入对象,在提高输入对象的索引计数为1
例子:
@interface MyClass:NSObject
@property (nonatomic, copy) NSString *myString;
这里定义了一个NSString类型的属性,不需要原子操作,所以用nonatomic.
为什么需要copy,而不是retain呢! 因为如果对myString赋值原字符串是一个可变的字符串(NSMutableString)对象的话,用retain的话,当原字符串改变的时候你的myString属性也会跟着变掉。我想你不希望看到这个现象。
@property (nonatomic, retain) UIView *myView;
这里定义了一个UIView类型的属性,不需要原子操作,所以用nonatomic.
当对myView 赋值的时候原来的UIView对象retainCount会加1
@implementation MyClass
@synthesize myString;
@synthesize myView;
MyClass *object=[[MyClass alloc] init];
NSMutableString *mutString=[NSMutableString stringWithString:"hello"];
object.myString=mutString;
[mutString appendString:@"world!"];
NSLog(@"%@",mutString); 输出为“hello world!”;
NSLog(@"%@",object.myString); 输出为"hello",因为myString在mutString改变之前已经copy了一份副本
UIView *view=[[UIView alloc] init];
view的retainCount为1;
object.myView=view;
此时view的retainCount为2,因为myView对View进行了一次retain。
[view release];
此处虽然view被release释放掉了,但是myView对view进行了一次retain,那么myView保留的UIView的对象指针仍然有效。
[object release];
二、ARC模式
iOS中的ARC是随着xcode4.2一起引入的,4.2版本以前的xcode是没有这种特性的,ARC只能在iOS4 和iOS5上使用,而weak关键字只能在iOS5上使用,并且只能是工程在ARC管理内存的时候才能用。
前段时间看到别人的代码中出现了unsafe_unretained的关键字,虽然自己了解它是出自arc中的关键字,但是为了了解的更加透彻,所以上网收集了一些相关知识来记录一下,以备以后查阅;
先 来了解一下各个关键字之间的关系,和其是否拥有所有权(及保留)属性值关键字所有权strong __strong有weak__weak无unsafe_unretained__unsafe_unretained无copy__strong有 assign__unsafe_unretained无retain__strong有
strong
该属性值对应 __strong 关键字,即该属性所声明的变量将成为对象的持有者。
weak
该属性对应 __weak 关键字,与 __weak 定义的变量一致,该属性所声明的变量将没有对象的所有权,并且当对象被破弃之后,对象将被自动赋值nil。
并且,delegate 和 Outlet 应该用 weak 属性来声明。同时,iOS 5 之前的版本是没有 __weak 关键字的,所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。
unsafe_unretained
等效于__unsafe_unretaind关键字声明的变量;像上面说明的,iOS 5之前的系统用该属性代替 weak 来使用。
(这里需要说明一下:应尽量不要使用unsafe_unretained来声明属性,因为如果它所指向的对象被释放了,那么它将变成一个野指针,而不会是nil,如果程序试图访问该野指针就会造成crash)
copy
与 strong 的区别是声明变量是拷贝对象的持有者。
assign
一般Scalar Varible用该属性声明,比如,int, BOOL。
retain
该属性与 strong 一致;只是可读性更强一些。
读写相关的属性 (readwrite, readonly)
读写相关的属性有 readwrite 和 readonly 两种,如果使用ARC之后,我么需要注意一下 readonly 属性的使用。
比如下面的变量声明。
@property (nonatomic, readonly) NSString *name;
一般声明为 readonly 的变量按理说应该不需要持有所有权了,但是在ARC有效的情况下,将出现下面的错误信息 :
“ARCforbidssynthesizingapropertyofanObjective-C object with unspecified ownership or storage attribute 如果定义了ARC有效,那么必须要有所有者属性的定义;所以我们的代码改成这样,就OK了
@property (nonatomic, strong, readonly) NSString *name;
不过有一点,Scalar Varible的变量缺省都有 assign 的属性定义,所以不需要给他们单独的明示声明了。
有一个关键字需要特别注意一下,就是__autoreleasing
在没有开启ARC的情况下,我们可以在一个函数中使用autorelease让某个对象延迟释放,但是在开启ARC的情况下是不会通过编译,如下:
在开启ARC的情况下,我们就需要使用如下方式进行替代:
-(ClassA *)TestMethod{ __autoreleasing ClassA *classA = [ClassA alloc] init]; return classA;}或:
-(NSString *)TestMethod:(_autoreleasing ClassA *)classA{ classA = [[ClassA alloc] init]; return classA;}ARC机制让我们节省了很多代码的编写,并且也让程序在效率方面有了很大的提升,所以充分利用这个新特性对我们是非常有帮助的,但是不建议新手使用,因为它会让我们知其然而不知其所以然。