@property 声明时的参数释放

来源:互联网 发布:cdn是什么 知乎 编辑:程序博客网 时间:2024/06/05 15:22

属性分为3类:

1.读写属性(Writability)包含:readwrite / readonly

2.setter语义(Setter Semantics)包含:assign / retain / copy

3.原子性(Atomicity)包含:nonatomic

下面具体说明各个属性的含义

readwrite / readonly:

决定是否生成set访问器,readwrite是默认属性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。
readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用。

assign / retain / copy:

这些属性用于指定set访问器的语义,也就是说,这些属性决定了以何种方式对数据成员赋予新值。

assign:

直接赋值,索引计数不改变,适用于简单数据类型,例如:NSIngeter、CGFloat、int、char等。

retain:

指针的拷贝,使用的是原来的内存空间。
对象的索引计数加1。
此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。

copy:

对象的拷贝,新申请一块内存空间,并把原始内容复制到那片空间。
新对象的索引计数为1。
此属性只对那些实行了NSCopying协议的对象类型有效。

很多Objective-C中的object最好使用用retain,一些特别的object(例如:string)使用copy。


nonatomic:

非原子性访问,不加同步,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问。默认值是atomic,为原子操作。
(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)


@property和@synthesize有以下两个作用:

1.作用一

@property是在头文件.h中声明一个变量的setter和getter方法。

@synthesize是在.m文件中定义setter和getter方法的实现。

2.作用二

@property,在声明变量方法的时候可以附加定义该变量的属性。如retain,assign,readonly,nonautomic等等。


但是,有一个点需要解释一下,就是直接使用 变量名赋值 和使用 self.变量 赋值的区别。比如

.h
ObjctName*  nameVarPtr;
@property(nonautomic,retain) ObjctName*  nameVarPtr;

.m

self.nameVarPtr = [[ObjectName alloc] init];
int n = [self.nameVarPtr retainCount];                      // n = 2 


nameVarPtr = [[ObjectName alloc] init];
n = [nameVarPtr retainCount];                                  // n = 1

self.nameVarPtr = [[ObjectName alloc] init] 和 nameVarPtr = [[ObjectName alloc] init] 两种赋值方式区别何在呢?

self.nameVarPtr=xxx 这种赋值方式等价于调用 [self setnameVarPtr:xxx], 而setnameVarPtr:xxx的方法的实现又是依赖于@property的属性的,比如retain,assign等属性。

nameVarPtr = xxx 的赋值方式,仅仅是对一个指针进行赋值。nameVarPtr仅仅是一个指针变量,记录了xxx的地址。在这个过程中不会调用setter方法,不会调用setter方法,就和@property没有关系,从而,也和retain,assign等属性没有关系。这种赋值方式就是一个简单的指针赋值。

综上,对成员变量进行赋值,为防内存泄露需要注意的点:

1.self调用setter方法的方式

ObjectName*  tmp= [[ObjectName alloc] init];

self.nameVarPtr =tmp;                 //retainCount=2

[tmp release];                               //retainCount=1

2.指针赋值方式,不会调用setter方法

nameVarPtr= [[ObjectName alloc] init]; // retainCount=1


/########################################################################################################################/


@property (nonatomic, assign) NSString *title; 
什么是assign,copy,retain之间的区别? 

1,getter=getterName,setter=setterName,设置setter与getter的方法名
2,assign: setter方法直接赋值,不进行任何retain操作,不更改索引计数(Reference Counting),为了解决原类型与环循引用问题。
3,retain:setter方法对参数进行release旧值再retain新值,所有实现都是这个顺序;释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1。
4,copy:setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1,这是为了减少对上下文的依赖而引入的机制;建立一个索引计数为1的对象,然后释放旧对象。
nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,则默认是两个访问方法都为原子型事务访问。锁被加到所属对象实例级。

retain的实际语法为: 
- (void)setName:(NSString *)newName { 
    if (name != newName) { 
       [name release]; 
       name = [newName retain]; 
       // name’s retain count has been bumped up by 1 
    } 


如果你不懂怎么使用他们,那么就这样 -> 
使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等) 
使用copy: 对NSString 
使用retain: 对其他NSObject和其子类 

nonatomic关键字: 
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。


/####################################################################################################################/


使用@property配合@synthesize可以让编译器自动实现getter/setter方法,使用的时候也很方便,可以直接使用对象.属性的方法调用;
如果我们想要对象.方法的方式来调用一个方法并获取到方法的返回值,那就需要使用@property配合@dynamic了。
其实使用@dynamic关键字是告诉编译器由我们自己来实现访问方法。如果使用的是@synthesize,那么这个工作编译器就会帮你实现了。

readonly
此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。

readwrite
此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。

assign
对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)
此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是可拷贝的。

retain
对其他NSObject和其子类    对参数进行release旧值,再retain新值
指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)。

copy
对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。

注释:
Copy其实是建立了一个相同的对象,而retain不是:
比如一个NSString 对象,地址为0×1111 ,内容为@”STR”
Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化
retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1
也就是说,retain 是指针拷贝,copy 是内容拷贝。

nonatomic
禁止多线程,变量保护,提高性能
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值


0 0