「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
属性
属性 (property) 是 OC 语言的一项特性,用来封装对象中的数据。使用属性,编译器就会自动编写访问这些属性所需要的方法,此过程叫做 自动合成 (aitosynthesis)
。
@property
iOS 最常见最常用的属性声明,会帮我们自动生成 setter 和 getter 方法声明。属性的本质是 ivar
+ setter
+ getter
。
@synthesize
帮我们自动实现 setter
方法和 getter
方法以及 _ivar
。
@dynamic
告诉编译器不用帮我们实现 @synthesize ,我们会在运行时提供这些方法的实现。
属性添加的实例变量是在属性前添加下划线,以此作为实例变量的名字。也可以在类的实现代码,通过 @synthesize
语法来指定实例变量的名字。
@implementation GBYObj
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
如果你只实现了其中一个存取方法 setter
或者 getter
方法,那么另一个还是会由编译器来合成。但是需要注意的是,如果你实现了属性所需的全部方法(如果属性是 readwrite 则需实现 setter
和 getter
方法,如果是 readonly
则只需实现 getter
方法),那么编译器就不会自动进行 @synthesize
,这时候就不会生成该属性的实例变量,需要根据实际情况自己手动 @synthesize
一下。
若不想编译器自动合成存取方法,则可以自己实现。那就是使用 @dynamic
它会告诉编译器:不要创建属性所用的实例变量,也不要去实现属性的存取方法,而且,在编译访问属性时,即使编译器发现属性没有定义存取方法,也不会报错,它相信这些方法需要在运行期找到。
/**
创建一个子类,继承自 CoreData 框架中 NSManagedObject 类,需要在运行期动态创建存取方法。
之所以这样做,因为子类的某些属性不是实例变量,其数据来自后端的数据库中
*/
@interface GBYObj: NSManagedObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@end
@implementation GBYObj
@dynamic firstName, lastName;
@end
属性特质
属性可以拥有的的特质分为四类
原子性
默认情况下,编译器所合成的方法会通过锁定机制来保证其原子性,如果属性具备 nonatomic
,则不使用同步锁。
atomic
原子性(默认修饰符), 基本不会使用,会严重影响性能。
nonatomic
非原子性
读写权限
readwrite
:读写属性,拥有 获取方法(getter)
与 设置方法 (setter)
。若该属性由 @synthesize
实现,则编译器自动生成这两个方法。
readonly
:只读属性,仅拥有 获取方法(getter)
,只有当该属性由 @synthesize
实现时,编译器才会为其合成获取方法。
内存管理
assign
:只会针对 纯量类型的 (scalar type,例如 CGFloat、NSInteger、BOOL等)
的简单赋值操作。既可以修饰对象,也可以修饰基本数据类型。修饰基本数据类型时,不会增加引用计数。
weak
:此特质表示该属性一种 非拥有关系
。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质和 assgin
类似,不过该属性所指的对象在销毁时,属性值也会清空(nil out)。只能修饰对象类型,不会增加引用计数。
strong
:此特质表示该属性一种 拥有关系
。为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后将新值设置上去。引用计数会 +1。
copy
:此特质表达的所属关系和 strong
类似,然而设置方法并不保留新值,而是将其 拷贝 (copy)
,当属性类型不可变时 (NSString、NSArray),常用此特质来保护其封装性。因为传递给设置方法的新值有可能指向一个可变的实例。
unsafe_unretained
:此特质和 assign
相同,但是它适用于 对象类型 (object type)
,该特质表示 非拥有关系
,当目标对象销毁时,属性值不会自动清空。ARC 下基本不会使用。
方法名
getter=<name>
指定 获取方法
的方法名。如果某属性是 Boolean类型,你想为其获取方法下添加 is
前缀,那么就可以用这个方法来指定。
/// eg switch 开关状态
@property (nonatamic, getter=isOn) BOOL on;
关于所有权修饰符
__weak
:弱引用持有对象,对应 weak 关键词,用来防止循环引用。
__strong
:强引用持有对象,可以对应 strong、retain、copy 关键字,编译器将 strong、retain、copy 修饰的属性生成带 __strong
修饰的实例变量。 一般和 __weak
成对出现,避免 __weak
修饰的对象提前释放,既避免了循环引用,又可以在作用域内部再次强引用一次。
__unsafe_unretained
:ARC 中一般不再使用。
参考
Effective Objective-C 2.0 编写高质量 iOS 与 OS X 代码的52个有效方法 - 书籍