@property指示符

在声明属性的时候一般会带上几个指示符,常用指示符有:

声明属性的一般顺序是:线程安全、访问权限、内存管理

//线程安全
atomic/nonatomic 

//访问方式
readwrite/readonly

//内存管理
assign
strong
weak
copy
unsafe_unretained
retain

atomic/nonatomic

指定合成存取方法是否为原子操作,可以理解为是否线程安全,但在iOS上即时使用atomic也不一定是线程安全的,要保证线程安全需要使用锁机制

可以发现几乎所有代码的属性设置都会使用nonatomic,这样能够提高访问性能,在iOS中使用锁机制的开销较大,会损耗性能。

readwrite/readonly

readwrite是编译器的默认选项,表示自动生成getter和setter。

readonly表示只合成getter而不合成setter。

assign、weak、unsafe_unretained

assign表示对属性只进行简单的赋值操作,不更改所赋新值的引用计数,也不改变旧值的引用计数。常用于标量类型,如:NSInteger,NSUInteger,CGFloat,NSTimeInterval等。

assign也可以修饰对象如NSString等类型对象,上面说过使用assign修饰不会更改所赋新值的引用计数,也不改变旧值的引用计数。如果当所赋的新值引用计数为0时,对象被销毁但是属性并不知道,编译器不会将该属性置为nil,指针仍旧指向之前被销毁的内存,这时访问该属性会产生野指针错误并崩溃,因此使用assign修饰的类型一定要为标量类型。

使用weak修饰的时候同样不会增加所赋的新值的引用计数,也不减少旧值的引用计数,但当该值被销毁时,weak修饰的属性会被自动赋值为nil,这样就可以避免野指针错误。

使用unsafe_unretained修饰时效果与assign相同,不会增加引用计数,当所赋的值被销毁时不会被置为nil可能会发生野指针错误。unsafe_unretained与assign的区别在于,unsafe_unretained只能修饰对象,不能修饰标量类型,而assign两者均可修饰。

strong、weak

strong表示属性对所赋的值持有强引用,表示一种“拥有关系”(owning Relationship)。使用该属性会先保留新值(即:增加新值的引用计数),然后再释放旧值(即:减少旧值的引用计数)。该属性只能修饰对象,如果对一些对象需要保持强引用则使用strong。

weak表示对所赋的值对象持有弱引用,表示一种“非拥有关系”(nonowning Relationship)。使用该属性对新值不会增加引用计数,也不会减少旧值的引用计数。所赋的值在引用计数为0被销毁后,weak修饰的属性会被自动置为nil,能够有效防止野指针错误。

weak常用在修饰delegate等防止循环引用的场景。

retain

在ARC环境下使用较少,在MRC下使用效果与strong一致。

copy

copy修饰的属性会在内存里拷贝一份对象,两个指针指向不同的内存地址。

一般用来修饰有对应可变类型子类的对象。

如:NSString/NSMutableString,NSArray/NSMutableArray,NSDictionary/NSMutableDictionary等。

为确保这些不可变对象因为可变子类对象影响,需要copy一份备份,如果不使用copy修饰,使用strong或assign等修饰则会因为多态导致属性值被修改。

为了防止多态的影响,对NSString进行修饰时一般使用copy。

copy的题外话

先说明一下浅拷贝和深拷贝:

浅拷贝:指针拷贝,不产生新的对象,源对象的引用计数器加1;只是多了一个指向这块内存的指针,共用一块内存。

深拷贝:对象拷贝,会产生新的对象,源对象的引用计数器不变;两块内存是完全不同的,也就是两个对象指针分别指向不同的内存,互不干涉。

有时候我们需要copy一个对象,或是mutableCopy一个对象,这时需要遵守NSCopying和NSMutableCopying协议。需要来实现copyWithZone:和mutableCopyWithZone:两个方法,而不是重写copy和mutableCopy两个方法。

Foundation框架中的很多数据类型已经帮我们实现了上述两个方法,因此我们可以使用copy方法和mutableCopy方法来复制一个对象,两者的区别在于copy的返回值仍未不可变对象,mutableCopy的返回值为可变对象。

  copy mutableCopy
NS* 浅拷贝,只拷贝指针,地址相同 单层深拷贝,拷贝内容,地址不同
NSMutable* 单层深拷贝,拷贝内容,地址不同 单层深拷贝,拷贝内容,地址不同

由上述表格可以看出:

对于不可变类型,使用copy方法时是浅拷贝,只拷贝指针,因为内容是不会变化的。使用mutableCopy时由于返回可变对象因此需要一份拷贝,供其他对象使用。

对于可变类型,不管是copy还是mutableCopy均会进行深拷贝,所指向指针不同。

注:深拷贝还有单层和多层,会在后续的文章中继续说明

前文介绍copy修饰符的时候讲过,在修饰NSString这样的不可变对象的时候使用copy修饰,但其实当给对象赋一个NSString时仍旧只复制了指针而不是拷贝内容,原因同上

copy关键字的特点:

修改源对象的属性和行为,不会影响副本对象

修改副本对象的属性和行为,不会影响源对象

一个对象可以通过copy和mutableCopy方法来创建一个副本对象

copy:创建的是不可变副本(NSString,NSArray,NSDictionary)

mutableCopy:创建的是可变副本(NSMutableString,NSMutableArray,NSMutableDictionary)

猜你喜欢

转载自blog.csdn.net/weixin_39624536/article/details/83691205