新版本的xcode,準(zhǔn)確說6.3之后,可能會(huì)報(bào)警告:
Pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)
這是由于Swift中可選類型(optionals)導(dǎo)致的問題。用?來表示, x?表示x可以有值也可以沒有值(nil)。而在Objective-C中則沒有這一區(qū)分,x即可表示這個(gè)對象是optional,也可表示是non-optioanl。這樣就會(huì)造成一個(gè)問題:在Swift與Objective-C混編時(shí),Swift編譯器并不知道一個(gè)Objective-C對象到底是optional還是non-optional,因此這種情況下編譯器會(huì)隱式地將Objective-C的對象當(dāng)成是non-optional。
為了解決這個(gè)問題,蘋果在Xcode 6.3引入了一個(gè)Objective-C的新特性:nullability annotations。這一新特性的核心是兩個(gè)新的類型注釋:__nullable和__nonnull。從字面上我們可以猜到,__nullable表示對象可以是NULL或nil,而__nonnull表示對象不應(yīng)該為空。當(dāng)我們不遵循這一規(guī)則時(shí),編譯器就會(huì)給出警告。
不過,為了安全起見,蘋果還制定了幾條規(guī)則:
- typedef定義的類型的nullability特性通常依賴于上下文,即使是在Audited Regions中,也不能假定它為nonnull。
- 復(fù)雜的指針類型(如id *)必須顯示去指定是nonnull還是nullable。例如,指定一個(gè)指向nullable對象的nonnull指針,可以使用”__nullable id * __nonnull”。
- 我們經(jīng)常使用的NSError **通常是被假定為一個(gè)指向nullable NSError對象的nullable指針。
兼容性
因?yàn)镹ullability Annotations是Xcode 6.3新加入的,所以我們需要考慮之前的老代碼。實(shí)際上,蘋果已以幫我們處理好了這種兼容問題,我們可以安全地使用它們:
- 老代碼仍然能正常工作, 即使對nonnull對象使用了nil也沒有問題。
- 老代碼在需要和swift混編時(shí),在新的swift編譯器下會(huì)給出一個(gè)警告。
- nonnull不會(huì)影響性能。事實(shí)上,我們?nèi)匀豢梢栽谶\(yùn)行時(shí)去判斷我們的對象是否為nil。
如果需要每個(gè)屬性或每個(gè)方法都去指定nonnull和nullable,是一件非常繁瑣的事。蘋果為了減輕我們的工作量,專門提供了兩個(gè)宏:NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。在這兩個(gè)宏之間的代碼,所有簡單指針對象都被假定為nonnull,因此我們只需要去指定那些nullable的指針。例如:
@interface SMLBaseUserDetailsVC : UIViewController < UICollectionViewDelegate>
NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) IBOutlet UIScrollView *detailsScrollView;
@property (nonatomic, readonly) IBOutlet UICollectionView *photoCV;
@property (nonatomic, weak, readonly) SMLUser *user;
- (IBAction)flagUser:(id)sender;
- (IBAction)closeAction:(nullable id)sender;
- (void) prefetchPhotos;
NS_ASSUME_NONNULL_END
@end