[iOS] 属性关键字
前言
属性关键字是一个非常重要的部分在 iOS 开发中,这篇博客是对前面内容的复习以及一些补充。
属性关键字
@propety
属性用于封装对象中的数据,属性的本质是 ivar(实例变量) + setter + getter。
可以用 @property 语法来声明属性,@property 会帮我们自动生成属性的 setter 和 getter 方法的声明。
@synthesize
这是用于自动合成 setter + getter 方法的实现,目前已经不需要这个关键字来帮助我们来实现 setter + getter 方法了,现在可以自动生成相关的方法,可以通过这个关键字来定制我们的 ivar 的名字。
就比如举个例子
@property (nonatomic, strong) NSString *name;
如果我这么写编译器会默认生成一个实例变量*_name这时会自动@synthesize name =_name这样其实self.name实际上就是访问_name*。
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@end@implementation Person
// 手动指定 ivar 名字
@synthesize name = myCustomName;
@end
这时self.name其实是访问myCustomName。
@dynamic
这个是让我们的编译器不用自动进行*@synathesize*,我们会自己实现,无需产生警告,但是他不会影响*@property*生成的 getter 和 setter 方法的声明,这里体现的是 OC 是一种动态运行的语言。
分类中有关@property 的使用
分类中可以通过*@property这个语法来添加属性,但是这里不会生成对应的实例变量,我们不可以用@synathesize*来合成成员变量。原因是
- Category 不能添加成员变量因为运行期内存布局已经固定,如果添加实例变量会破坏类的内部布局。
- @synthesize是用来合成成员变量的,而分类中不可以添加成员变量。
重要的几个属性关键词
原子性
-
atomic
- 含义:生成 getter/setter 是线程安全的,会加锁。
- 优点:保证多线程小爱取值和赋值不会读写冲突。
- 缺点:性能差,开发中几乎不用。
-
nonatomic
- 含义:不保证线程安全,getter/setter 直接操作。
- 优点:性能好,开发中大部分用它。
内存管理相关
-
strong
- 含义:强引用,持有对象,引用计数 + 1;
- 适用:OC 对象的属性(NSString、NSArray、自定义类等)。
-
copy
- 含义:创建副本(调用 copy 方法),不受外部修改影响。
- 适用:NSString、NSArray、NSDictionary(尤其是 NSString 防止外部传入 NSMutableString 改变值)。
下面有段代码可以形象的展示出 copy 和 strong 的区别
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Person1 : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) BOOL age;
@endNS_ASSUME_NONNULL_END
#import <Foundation/Foundation.h>
#import "Person1.h"
int main(int argc, const char * argv[]) {@autoreleasepool {Person1 *p1 = [[Person1 alloc] init];NSMutableString *s1 = [NSMutableString stringWithString:@"Apple"];p1.name = s1;[s1 appendString:@"Android"];NSLog(@"%@", p1.name);}return 0;
}
这是打印结果
如果我把属性中的copy换成strong那么打印结果会发生改变
这里的原因就是person.name的属性是copy,所以创建了新的字符串,这个属于深拷贝,拷贝出来一个新的对象,后面的操作都是对新的对象操作,而我们的实际调用还是原来的对象,所以值不会改变。
而改成strong以后,引用计数会加一本质上是浅拷贝,指针拷贝,这时我们操作,更改他的值就会使原本的对象发生改变。
-
weak
- 含义:弱引用,不增加引用计数。
- 特点:当对象释放时,weak 指针会自动置为nil,避免野指针。
- 适用:delegate 属性,或者避免循环引用。
-
assign
- 含义:直接赋值,不改变引用计数。
- 适用:基本数据类型(int、float、BOOL、struct)。
- 缺点:如果用于对象,会产生野指针。
总结
这里我给出一个表格来去介绍大部分的属性关键字
分类 | 关键字 | 作用 | 说明 |
---|---|---|---|
原子性 | atomic (默认) | 保证多线程读写安全 | 性能差,一般不用 |
nonatomic | 不保证线程安全 | 性能更好,iOS 开发中几乎都用这个 | 性能更好,iOS 开发中几乎都用这个 |
内存管理 | strong | 对象持有(引用计数 +1) | 常用于 OC 对象属性 |
weak | 不持有对象,释放后自动置 nil | 常用于避免循环引用(如 delegate) | 常用于避免循环引用(如 delegate) |
assign | 直接赋值,不改变引用计数 | 适合基本数据类型(int、float、struct),对对象可能产生野指针 | 适合基本数据类型(int、float、struct),对对象可能产生野指针 |
unsafe_unretained | 和 assign 类似,但对象释放不会置 nil | ARC 前常用,ARC 后几乎不用 | ARC 前常用,ARC 后几乎不用 |
copy | 创建副本(调用 copy 方法) | 常用于 NSString、NSArray、NSDictionary 等不可变对象,防止外部修改 | 常用于 NSString、NSArray、NSDictionary 等不可变对象,防止外部修改 |
读写性 | readwrite (默认) | 生成 getter & setter | 外部可读可写 |
readonly | 只生成 getter | 外部只读,可在类内写 | 外部只读,可在类内写 |
方法名 | getter=methodName | 自定义 getter 方法名 | 如 getter=isFinished |
setter=methodName | 自定义 setter 方法名 | 如 setter=setFinishedState: | 如 setter=setFinishedState: |
多线程(很少用) | atomic | 多线程安全 | 系统默认,但实际开发常配合 nonatomic |