简介
属性(property)是Objective-C的一项特性,用于封装对象中的数据。Objective-C对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法”(getter)用于读取变量值,而“设置方法”(setter)用于写入变量值。这个概念已经定型,并且经由“属性”这一特性而成为Objective-C 2.0 的一部分,开发者可以令编译器自动编写与属性相关的存取方法。此特性引入了一种新的“点语法”(dot syntax),使开发者可以更为容易地依照类对象来访问存放于其中的数据。
属性声明
语法格式:@property (参数1, 参数2...) 类型 名字;
#import <Foundation/Foundation.h>
@interface Person : NSObject
// 属性生命
// 关键字 参数1 参数2 类型 名字
@property (strong, nonatomic) NSString *name;
@end
Tips
1、属性声明中的参数,将会在后文详细讲解;
属性的声明,需声明在@interface和@end之间,全局变量的下方,与方法的声明类似。
在 iOS4.4 之前,我们需要用到另一个属性关键字@synthesize,他的意义在于,将一个属性与对应的全局变量合成,这个关键字在iOS4.4以后不必再写出,系统会自动添加,但是实例变量依旧可用;
@synthesize name = _name;
在 iOS4.4 以后,使用前面的方法声明了一个属性即可直接使用,但是我们依然需要了解一个属性的完整诞生过程,它能帮我们更好的使用属性;
声明一个属性本质上就是指定一个set和取值方法,所以像前面提到的那些set和取值,都不写出,但是方法依旧可用。
iOS5之前和iOS5之后,属性在定义形式上做了一定的简化,不重写setter()和getter()方法时,也可不使用@synthesize 关键字,且成员变量不必写出,也能自动生成一个带下划线的同名成员变量;
iOS5之前,书写属性的步骤:
1) 先写出带下划线的成员变量;如 NSString * _name;
2) 使用@property 配备一个不带下划线,且与成员变量同名的属性;
@property(nonatomic , retain) NSString * name;
3)使用关键字@synthesize将成员变量和属性名进行合成;
@synthesize name = _name;
属性关键字
@property后面的()内可以配置一些参数,配置了参数后,编译器会为我们生成不同的getter和setter方法,下面我们来看看有哪些可配置的参数:
读写属性
读写属性即控制了属性是否存在设置器方法,这些参数之间是互斥的。
readwrite(默认): 表名了属性是可读可写的,即属性具有setter方法和getter方法,若该属性由@synthesize实现,则编译器会自动生成这两个方法;
readonly:表明属性是只读的,即属性只有获取器方法,将生成getter方法而不生成setter方法。如果视图对该属性使用点语法赋值,将引起编译器错误,只有当该属性由@synthesize实现时,编译器才会为其合成获取方法;
原子性
automic(默认):这个属性是为了保证程序在多线程情况,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题;
nonatomic:该属性不提供多线程保护,如果该对象无需考虑多线程的情况,请加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率;
内存管理语义
属性用于封装数据,而数据则要有“具体的所有权语义”。下面这一组特质仅会影响“设置方法”。例如,用“设置方法”设定一个新值时,它应该是“保留(retain)”此值呢,还是只将其赋给底层实例变量就好?编译器在合成存取方法时,要根据此特质来决定所生成的代码。如果自己编写存取方法,那么久必须同有相关属性所具备的特质相符。
retain:对象使用,持有对象,retainCount + 1;
assion:这个属性一般用来处理基础类型,比如int、float等待,如果你声明的属性是基础类型的话,assign是默认的,你可以不加这个属性;
strong:此特质表明该属性定义了一种“拥有关系”。为这种属性设置新值时,设置方法会先保留新值,释放旧值,然后再将新值设置上去。主要用于修饰强引用的属性;
weak:此特质表明该属性定义了一种“非拥有关系”。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assin类似,然而在属性所指的对象遭到摧毁时,属性值也会清空。主要用于修饰弱引用的属性,当弱引用的对象被释放后,该对象将被自动赋予nil值;
copy:此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝”。当属性类型为NSString*时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可以修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变”的字符串,确保对象中的字符串值不会无意间变动,只要实现属性所用的对象是“可变的”,就应该在设置新属性时拷贝一份。我们可以暂时这样理解,当它使用在不可变类型的属性时,等于strong;当它使用在可变类型时,每次赋值都会拷贝一个新的对象。
unsafe_unretained:此特质语义和assin相同,但是它适合用于“对象类型”,该特质表达一种“非拥有关系”,当目标对象遭到摧毁时,属性值不会自动清空(置为nil),这一点与weak有区别。
方法名
可通过如下特质来制定存取方法的方法名:
getter=< name >:指定“获取方法”的方法名。如果某属性时Boolean型,而你想为其获取方法加上is前缀,那么就可以用这个方法来指定。比如说,在登陆界面,表示登陆状态的属性就是这样定义的:
@property (nonatomic, assign, getter=isLogin) BOOL login;
1
setter=< name >:指定“设置方法”的方法名,这种用法不太常见,用法与getter=<name>一致;
Tips
1、一般情况下,只要是对象类型,都使用strong(后面可能有例外);
2、只要是非对象类型,都使用assign;
3、ARC模式下
weak 相当于 assign 相当于,但不等价,注意;
strong 相当于 retain 相当于;
点语法
点语法简介
有了属性,我们就可以使用另外一个语法:点语法。使用方法如下:
person.name = @"Admin"; // 设置器方法
NSString *name = person.name; // 访问器方法
Tips
1、第一个左边部分相当于一个设置器方法;
2、第二个右边部分相当于一个访问器方法;
3、点语法是objective-C 2.0 的新特性。一般声明完属性之后才能使用点语法;
点语法有点
方便程序员能够很快地转到OC上来;
让程序设计简单化;
隐藏了内存管理细节;
隐藏了多线程、同步、加锁细节;
点语法缺点
性能有点差,内部转化为setter,getter;
不易理解苹果的调用机制;
补充
在dealloc方法中,我们可以采用一种高明的技巧;
self.name = nil;
// 这行代码表示使用nil参数调用setAge:方法。生成的访问器方法将自动释放以前的age对象,并使用nil值替代,这样可以使我们避免对已有释放内存的悬空引用问题。