iOS 属性及修饰符 - 面试回顾

378 阅读4分钟

「这是我参与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 则需实现 settergetter 方法,如果是 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个有效方法 - 书籍