天天看点

Objective-c中@property声明时的参数释疑

 @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 ,那么访问器只是简单地返回这个值