分类 | 属性关键字 |
---|---|
原子性 | atomic、nonatomic |
读写权限 | readwrite、readonly、setter、getter |
内存管理 | assign、weak、unsafe_unretained、retain、strong、copy |
可空性 | (nullable、_Nullable 、__nullable)、 (nonnull、_Nonnull、__nonnull)、 (null_unspecified、_Null_unspecified 、__null_unspecified)、 null_resettable |
属性关键字 | 用法 |
---|---|
atomic | 原子性(默认),编译器会自动生成互斥锁,对 setter 和 getter 方法进行加锁,能够保证属性的赋值和取值的原子性操做是线程安全的,但不包括操做和访问。 好比说 atomic 修饰的是一个数组的话,那么咱们对数组进行赋值和取值是能够保证线程安全的。可是若是咱们对数组进行操做,好比说给数组添加对象或者移除对象,是不在 atomic 的负责范围以内的,因此给被 atomic 修饰的数组添加对象或者移除对象是没办法保证线程安全的。 |
nonatomic | 非原子性,通常属性都用 nonatomic 进行修饰,由于 atomic 很是耗时。 |
属性关键字 | 用法 |
---|---|
readwrite | 可读可写(默认),同时生成 setter 方法和 getter 方法的声明和实现。 |
readonly | 只读,只生成 getter 方法的声明和实现。 |
setter | 能够指定生成的 setter 方法名,如 setter = setName。 |
getter | 能够指定生成的 getter 方法名,如 getter = getName。 |
属性关键字 | 用法 |
---|---|
assign | 1. 既能够修饰基本数据类型,也能够修饰对象类型; 2. setter 方法的实现是直接赋值,通常用于基本数据类型 ; 3. 修饰基本数据类型,如 NSInteger、BOOL、int、float 等; 4. 修饰对象类型时,不增长其引用计数; 5. 会产生悬垂指针(悬垂指针:assign 修饰的对象在被释放以后,指针仍然指向原对象地址,该指针变为悬垂指针。这时候若是继续经过该指针访问原对象的话,就可能致使程序崩溃)。 |
weak | 1. 只能修饰对象类型; 2. ARC 下才能使用; 3. 修饰弱引用,不增长对象引用计数,主要能够用于避免循环引用; 4. weak 修饰的对象在被释放以后,会自动将指针置为 nil,不会产生悬垂指针。 |
unsafe_unretained | 1. 既能够修饰基本数据类型,也能够修饰对象类型; 2. MRC 下常用,ARC 下基本不用; 3. 同 weak,区别就在于 unsafe_unretained 会产生悬垂指针。 |
retain | 1. MRC 下使用,ARC 下基本使用 strong; 2. 修饰强引用,将指针原来指向的旧对象释放掉,而后指向新对象,同时将新对象的引用计数加1; 3. setter 方法的实现是 release 旧值,retain 新值,用于OC对象类型。 |
strong | 1. ARC 下才能使用; 2. 原理同 retain; 3. 可是在修饰 block 时,strong 至关于 copy,而 retain 至关于 assign。 |
copy | setter 方法的实现是 release 旧值,copy 新值,用于 NSString、block 等类型。 |
Apple Blog:Nullability and Objective-C程序员
苹果在 Xcode 6.3 引入的一个 Objective-C 的新特性nullability annotations
。这些关键字能够用于属性、方法返回值和参数中,来指定对象的可空性,这样编写代码的时候就会智能提示。在 Swift 中可使用?
和!
来表示一个对象是optional
的仍是non-optional
,如UIView?
和UIView!
。而在 Objective-C 中则没有这一区分,UIView
便可表示这个对象是optional
,也可表示是non-optioanl
。这样就会形成一个问题:在 Swift 与 Objective-C 混编时,Swift 编译器并不知道一个 Objective-C 对象究竟是optional
仍是non-optional
,所以这种状况下编译器会隐式地将 Objective-C 的对象当成是non-optional
。引入nullability annotations
一方面为了让 iOS 程序员平滑地从 Objective-C 过渡到 Swift,另外一方面也促使开发者在编写 Objective-C 代码时更加规范,减小同事之间的沟通成本。面试
关键字__nullable
和__nonnull
是苹果在 Xcode 6.3 中发行的。因为与第三方库的潜在冲突,苹果在 Xcode 7 中将它们更改成_Nullable
和_Nonnull
。可是,为了与 Xcode 6.3 兼容,苹果预约义了宏__nullable
和__nonnull
来扩展为新名称。同时苹果一样还支持没有下划线的写法nullable
和nonnull
,它们的区别在与放置位置不一样。swift
注意:此类关键词仅仅提供警告,并不会报编译错误。只能用于声明对象类型,不能声明基本数据类型。数组
属性关键字 | 用法 |
---|---|
nullable、_Nullable 、__nullable | 对象能够为空,区别在于放置位置不一样 |
nonnull、_Nonnull、__nonnull | 对象不能为空,区别在于放置位置不一样 |
null_unspecified、_Null_unspecified 、__null_unspecified | 未指定是否可为空,区别在于放置位置不一样 |
null_resettable | 1. getter 方法不能返回为空,setter 方法能够为空; 2. 必须重写 setter 或 getter 方法作非空处理。不然会报警告 Synthesized setter 'setName:' for null_resettable property 'name' does not handle nil |
@property (nonatomic, copy, nullable) NSString * param; @property (nonatomic, copy) NSString * _Nullable param; @property (nonatomic, copy) NSString * __nullable param; 复制代码
- (nullable NSString *)method; - (NSString * _Nullable)method; - (NSString * __nullable)method; 复制代码
- (void)methodWithParam:(nullable NSString *) param; - (void)methodWithParam:(NSString * _Nullable) param; - (void)methodWithParam:(NSString * __nullable) param; 复制代码
双指针类型对象
、Block 的返回值
、Block 的参数
等,这时候就不能用nonnull/nullable
修饰,只能用带下划线的__nonnull/__nullable
或者 _Nonnull/_Nullable
:- (void)methodWithError:(NSError * _Nullable * _Nullable)error - (void)methodWithError:(NSError * __nullable * __nullable)error; 复制代码
- (void)methodWithBlock:(nullable id __nonnull (^)(id __nullable params))block; 复制代码
@interface AAPLList : NSObject <NSCoding, NSCopying> // ... - (AAPLListItem * _Nullable)itemWithName:(NSString * _Nonnull)name; @property (copy, readonly) NSArray * _Nonnull allItems; // ... @end // -------------- [self.list itemWithName:nil]; // warning! 复制代码
若是每一个属性或每一个方法都去指定nonnull
和nullable
,将是一件很是繁琐的事。苹果为了减轻咱们的工做量,专门提供了两个宏:NS_ASSUME_NONNULL_BEGIN
和NS_ASSUME_NONNULL_END
。在这两个宏之间的代码,全部简单指针类型都被假定为nonnull
,所以咱们只须要去指定那些nullable
指针类型便可。示例代码以下:安全
NS_ASSUME_NONNULL_BEGIN @interface AAPLList : NSObject <NSCoding, NSCopying> // ... - (nullable AAPLListItem *)itemWithName:(NSString *)name; - (NSInteger)indexOfItem:(AAPLListItem *)item; @property (copy, nullable) NSString *name; @property (copy, readonly) NSArray *allItems; // ... @end NS_ASSUME_NONNULL_END // -------------- self.list.name = nil; // okay AAPLListItem *matchingItem = [self.list itemWithName:nil]; // warning! 复制代码
nonnull/nullable
;_Nonnull/_Nullable
,建议弃用__nonnull/__nullable
。为了安全起见,苹果还制定了如下几条规则:markdown
typedef
类型的的可空性一般依赖于上下文,即便在 Audited Regions 中也不能假定它为nonnull
;id *
)必须明确指定它的可空性。例如,指定一个指向nullable
对象的nonnull
指针,可使用_Nullable id * _Nonnull
;NSError **
常常用于经过方法参数返回错误,所以始终假定它是指向nullable
的NSError
对象的nullable
的指针。全部权修饰符 | 用法 |
---|---|
__strong | 1. 强引用持有对象,能够对应 strong、retain、copy 关键字。 2. 编译器将为 strong、retain、copy 修饰的属性生成带 __strong 全部权修饰符的实例变量。 |
__weak | 1. 弱引用持有对象,对应 weak 关键字,ARC下用来防止循环引用。 2. 编译器将为 weak 修饰的属性生成带 __weak 全部权修饰符的实例变量。 |
__unsafe_unretained | 1. 弱引用持有对象,对应 unsafe_unretained、assign 关键字,MRC下用来防止循环引用。 2. 编译器将为 unsafe_unretained 修饰的属性生成带 __unsafe_unretained 全部权修饰符的实例变量。 3. 与 __weak 相比,它不须要遍历 weak 表来检查对象是否 nil,性能上要更好一些。可是它会产生悬垂指针。 |
__autoreleasing | 在 MRC 中咱们能够给对象发送 autorelease 消息来将它注册到 autoreleasepool 中,而在 ARC 中咱们可使用 __autoreleasing 修饰符修饰对象将对象注册到 autoreleasepool 中。 |
关于全部权修饰符的详细解释,能够参阅《iOS - 老生常谈内存管理(三):ARC 面世》。网络
答: 编译器会自动生成互斥锁,对 setter 和 getter 方法进行加锁,能够保证属性的赋值和取值原子性操做是线程安全的,但不包括操做和访问。
好比说atomic
修饰的是一个数组的话,那么咱们对数组进行赋值和取值是能够保证线程安全的。可是若是咱们对数组进行操做,好比说给数组添加对象或者移除对象,是不在atomic
的负责范围以内的,因此给被atomic
修饰的数组添加对象或者移除对象是没办法保证线程安全的。app
weak/__weak
弱引用修饰,经常使用于对delegate
和block
的修饰;weak
。weak
只能修饰对象,而assign
既能够修饰对象也能够修饰基本数据类型;assign
修饰的对象在被释放后,指针仍然指向原对象地址;而weak
修饰的对象在被释放以后会自动置指针为 nil;assign
和weak
都不改变对象的引用计数。@property (copy) NSMutableArray *array; 复制代码
答: 不论赋值过来的是NSMutableArray
仍是NSArray
对象,进行copy
操做后都是NSArray
对象(深拷贝)。因为属性被声明为NSMutableArray
类型,就不可避免的会有调用方去调用它的添加对象、移除对象等一些方法,此时因为copy
的结果是NSArray
不可变对象,对NSArray
对象调用添加对象、移除对象等方法,就会产生程序异常。函数