苹果公司在Objective-C 2.0中引入了属性,它组合了新的预编译指令和新的属性访问器语法。Objective-C 2.0的特性只适用于Mac OSX 10.5(Leopard)以上的版本。
1.1 使用属性值
1.1.1 简化接口代码
@符号标志着“这是Objective-C语法”。@property是一种新的编译器功能,它意味着声明了一个新对象的属性。
@property预编译指令的作用是自动声明属性的setter和getter方法。
1.1.2 简化实现代码
@synthesize也是一种新的编译器功能,它表示“创建了该属性的访问代码”。这种预编译指令很强大,也许你永远也不会看到实现setter和getter方法的代码,但是这些方法确实存在并可以被调用。这种技术使苹果公司可以更加灵活地改变Objective-C中生成访问方法的方式,并获取更安全的实现和更高的性能。
所有的属性都是基于变量的。所以在你合成(synthesize)getter和setter方法的时候,编译器会自动创建与属性名称相同的实例变量。
属性=ivar(实例变量) + getter方法+setter方法,这是属性的本质。
需要注意以下两个问题:
① ivar、getter、setter如何生成并添加到类中:这是编译器自动合成的,通过@synthesize关键字指定,若不指定,默认为@synthesize propertyName = _propertyName; 若手动实现了getter和setter方法,则不会自动合成。现在编译器已经默认为我们添加@synthesize propertyName = propertyName; 因此不再需要手动添加了,除非你真的要该成员变量名。生成getter方法时,会判断当前属性是否有 , 比如声明属性为@property (nonatomic , copy)NSString *_name; 那么生成的成员变量名就会变成name(注意:此处是两个下划线), 如果我们要手动生成getter方法,就要判断是否以开头了。
② 命名要有规范,是不允许声明属性是使用开头的,不规范的命名,使用起来多有不便,所以,你最好遵循。
Xcode4.5以后,就不再使用@synthesize了。
1.1.3 点表达式的妙用
点表达式(.)看起来与C语言中的结构体访问以及Java语言中的对象访问有些相似,其实这是Objective-C的设计人员有意为之。如果点表达式出现在了等号的左边,该变量名称的setter方法将被调用。如果点表达式出现在了对象变量(或者等号)的右边,则该变量名称的getter方法将被调用。
点表达式指示调用访问方法的一种便捷方式。
1.2 属性扩展
复制字符串可以防止因意外的变化而产生不利影响。
保留死循环:它会令引用计数器发生故障。如果两个实体是拥有和被拥有的关系。比如A和B, A保留了B, 而B又保留了A, 那么这两个对象的引用计数的值永远不会归零,也永远不会被释放。它们都一直等待着对方先释放。所以一般的规则是所有者对象保留被拥有的对象,而不是被拥有者的对象保留所有者的对象。
声明属性时,你可以使用copy特性(针对字符串)或者保留和释放特性(针对对象),如果你两者都没有使用的话,编译器默认会使用assign。
你也可以使用nonatomic声明,如果不在多线程中使用,这些声明可以提高访问方法的调用速度。使用nonatomic特性对于性能的提升实际上起不了多大作用。不过iOS程序员经常会使用这种技术,从而在资源有限的设备上获得更好的性能。如果你不想保留某个变量对象,可以使用assign特性,这样可以避免发生保留死循环。
如果你没有为属性指定任何特性,它们会默认使用nonatomic和assign。你也可以为可保留的指针(即Objective-C)对象指定retain和copy特性,而其他C类型和不可保留的指针则必须使用assign特性并且要手动来管理内存。
1.2.1 名称的使用
一般情况下,属性的名称始终与支持属性的实例变量名称相同。不过有时候你也希望公开的属性是一个名称,而支持属性的实例变量是另一个名称,这样技术上也是行得通的。(声明一个实例变量,@synthesize 属性名称 = 实例变量名称)。在调用属性的setter和getter方法时实质上修改和返回的实例变量。
1.2.2 只读属性
属性默认具有可读可写特性。如果你想让某个对象具有只读属性,你可以使用关键字readonly。当编译器知道属性是只读的,它将只生产一个getter方法而不会生成setter方法。
1.2.3 自己有时动手更好
属性是基于变量的,并且编译器会为你创建getter和setter方法。
然而,你也可以使用关键字@dynamic来告诉便以为不要生成任何代码(getter和setter方法)或创建相应的实例变量。
使用getter=和setter=特性就可以自定义想要的setter和getter方法名称。但是,如果这样做的话,就会破坏键/值规则,因此除非有必须使用这些特性的原因,否则请尽量避免使用。
1.2.4 特性不是万能的。
属性只支持最简单的setter和getter方法,但是不支持那些需要接收额外参数的方法。
补充: @synthesize和@dynamic关键字的区别如下:
@property属性有两个对应的关键字,一个是 @synthesize,另一个是 @dynamic,如果 @synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var; @synthesize 的语义是你如果没有手动实现setter和getter方法,那么编译器会为你自动加上这两个方法。@dynamic告诉编译器: 属性的 setter和getter由用户自己实现,不自动生成。( 当然对于 readonly 的属性只需要提供 getter方法即可) 假如一个属性被声明为 @dynamic var,然后你没有提供 @setter和 @getter,编译的时候没问题,但是当程序运行到 instance.var = someVar ,由于缺setter方法会导致奔溃。或者当运行到 someVar = var时,由于缺 getter 方法同样导致奔溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
网友评论