@property属性关键字详解

@property的常用属性关键字有nonatomic、atomic、readonly、writeonly、readwrite、assign、retain、copy、strong、weak、unsafe_unretained、nonnull、nullable、null_resettable,看着挺多的,但是经常用的也就那几个。

  • atomic: 默认关键字,也就是说如果什么都不写,默认就是这个。表示该属性是线程同步的。一般用不到,会影响性能。

  • nonatomic: 非线程同步,基本都是用这个。

  • readwrite: 默认关键字,表示可读可写。

  • readonly: 只能读(get),不能写(set),当你希望属性不能被外界直接修改,但是可以访问时使用。

  • writeonly: 只能写(set),不能读(get)。一般用不到。

  • assign: 默认关键字。非对象类型一般使用此关键字。

  • retain: 对象的引用计数+1。ARC下已经不再使用此关键字,用strong代替。

  • copy: 拷贝一个新的对象,新对象的引用计数+1,原对象不变。

  • strong: 能够维持对象的生命。

下面说说一些重点和区别:

weak、assign的使用场景和异同

不希望持有对象时使用weak关键字,比如代理,UI控件(看过很多代码里面UI控件都是使用的strong,其实没有必要,因为父视图会持有子视图,会维持子视图的生命,父视图一旦死了,子视图也就跟着死了),避免循环引用的__weak等。 weak, assign都不会影响对象的引用计数。当一个对象的引用计数为0时,所有指向该对象的weak属性指针会被自动设置为nil,而assign属性不会,如果对象被释放了,此时再进行访问,程序崩溃。下面来验证一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@interface ViewController ()

@property (nonatomic, weak)   NSArray *array_weak;
@property (nonatomic, assign) NSArray *array_assign;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSArray *array_temp = @[@"哈哈"];
    self.array_weak = array;
    self.array_assign = array;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"array_weak - 地址:%p, 内容:%@", self.array_weak, self.array_weak);
    NSLog(@"array_assign - 地址:%p, 内容:%@", self.array_assign, self.array_assign);
}

在viewDidLoad里面创建了一个临时的NSArray对象,用weak和assign指针指向这个对象。然后点击屏幕的时候分别打印weak和assign属性的地址和内容,运行结果:

array_weak - 地址:0x0, 内容:(null) 

从结果可以看出array_weak有打印信息,已经自动指向nil,程序没有挂掉。但是array_assign并没有打印信息,程序执行到这里就挂了。从图中也可以看出错误所在,BAD_ACCESS错误,即是野指针。很好的验证了上面的说法。

weak和unsafe_unretained

unsafe_unretained从命名就可以看出意义所在,unsafe即是不会自动设置为nil,如果对象被释放了,再进行访问,程序会crash;unretained与weak类似,不会影响对象的引用计数。由于在iOS4下,还没有支持weak,所以如果在需要使用weak的场景(比如delegate),使用unsafe_unretained。这里就不验证了,验证方法跟上面差不多,有兴趣可以自行验证。

不要将copy用到NSMutableString,NSMutableArray,NSMutableDictionary等可变对象上,除非有特别的需求。

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface ViewController ()

@property (nonatomic, copy) NSMutableArray *mutableArray_copy;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableArray *mutableArray = [NSMutableArray arrayWithObject:@"哈哈"];
    self.mutableArray_copy = mutableArray;

    [self.mutableArray_copy addObject:@"呵呵"];
}

运行,直接挂了,报出经典错误: 

仔细观察错误,[__NSArrayI addObject:], __NSArrayI表示的是NSArray类型,NSArray是不可变数组,当然没有addObject:这个方法。那么问题来了,明明self.mutableArray_copy是可变类型,为什么变成了不可变类型。原因很简单,执行这一句self.mutableArray_copy = mutableArray;的时候,会调用mutableArray_copy的set方法,copy属性默认set方法是这样写的:

1
2
3
- (void)setMutableArray_copy:(NSMutableArray *)mutableArray_copy {
    _mutableArray_copy = [mutableArray_copy copy];
}

可以看到,set方法里面调用的是copy,而不是mutableCopy,结果自然是不可变的__NSArrayI类型。解决方式很简单:将copy关键字改为strong,如果确实有copy的需求,重写set方法,将copy改为mutableCopy即可。所以copy关键字要注意使用场景,不要乱用。

nonnull、nullable、null_resettable

这三个属性关键字是WWDC2015中介绍的OC新特性,与Swift中的?和!类似,算是一个简版的optional。nonnull就是说该属性不为nil,必须有值。相反,nullable表示可选的,可以为nil,类似Swift中的?。null_resettable表示setter是nullable,可选的,但是getter是nonnull,一定会有值返回。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值