Optional的定義
Optional是Objective-C沒有的數(shù)據(jù)類型喳张,是蘋果引入到Swift語(yǔ)言中的全新類型续镇,它可以有值,也可以沒有值销部,當(dāng)它沒有值時(shí)摸航,就是nil。此外柴墩,Swift的nil也和Objective-C有些不一樣忙厌,在Objective-C中,只有對(duì)象才能為nil江咳,而在Swift里逢净,當(dāng)基礎(chǔ)類型(整形、浮點(diǎn)歼指、布爾等)沒有值時(shí)爹土,也是nil,而不是一個(gè)初始值踩身,沒有初始值的值胀茵,是不能使用的,這就產(chǎn)生了Optional類型挟阻。Optional類型的值不能直接使用琼娘,需要拆包才可以取到值。
Nullability Annotations
Objective-C對(duì)象沒有區(qū)分是optional還是non-optional附鸽。Swift編譯器并不知道一個(gè)Objective-C對(duì)象是哪種類型脱拼,因此這種情況下編譯器會(huì)隱式地將Objective-C的對(duì)象當(dāng)成是non-optional。
XCode6.3引用Objective-C新特性解決這個(gè)問題:nullability annotations
The Core:_Nullable and _Nonnull
新特性的核心是增加兩個(gè)新的注釋:_Nullable 和 _Nonnull坷备。正如你所預(yù)料的, _Nullable表示對(duì)象可能是NULL或者nil,_Nonnull表示對(duì)象不能為空熄浓。 當(dāng)你沒有遵循規(guī)則時(shí)編譯器就會(huì)報(bào)錯(cuò)。
@interface AAPLList : NSObject <NSCoding, NSCopying>
// ...
- (AAPLListItem * _Nullable)itemWithName:(NSString * _Nonnull)name;
@property (copy, readonly) NSArray * _Nonnull allItems;
// ...
@end
// --------------
[self.list itemWithName:nil]; // warning!
在任何使用C const 關(guān)鍵字的地方都可以使用_Nullable 和 _Nonnull省撑,但僅限于使用在指針類型上赌蔑。然而在一般情況有更漂亮的方式書寫這些注釋:直接在圓括號(hào)后面使用不帶下劃線的nullable和nonnull俯在,只要它的類型是一個(gè)對(duì)象或者block指針。
- (nullable AAPLListItem *)itemWithName:(nonnull NSString *)name;
- (NSInteger)indexOfItem:(nonnull AAPLListItem *)item;
在聲明屬性時(shí)娃惯,也可以用同樣的方式和修飾符寫在一起跷乐。
@property (copy, nullable) NSString *name;
@property (copy, readonly, nonnull) NSArray *allItems;
不帶下劃線的形式更好看一些,但你仍然需要在你的頭文件里設(shè)置每一個(gè)類型石景。為了讓你更輕松劈猿,可以使用audited regions。
Audited Regions
為了更簡(jiǎn)單使用這些新注釋潮孽,可以在頭文件標(biāo)記一定區(qū)域?yàn)?em>nullability揪荣。在這個(gè)區(qū)域內(nèi),所有的指針類型會(huì)被假定為nonnull往史。
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!
為了安全要注意以下一條規(guī)則:
* typedef定義的類型要結(jié)合上下文看仗颈,不能假定它是nonnull
* 復(fù)雜的指針類型比如id *,一定要明確它的注釋椎例。例如一個(gè)指向nullable對(duì)象的non-nullable指針:_Nullable id * _Nonnull
* NSError **通常被假定指向nullable類型NSError的對(duì)象的nullable指針挨决,用來通過方法參數(shù)返回錯(cuò)誤。
Compatibility
* 編譯過的代碼可以正常運(yùn)行订歪,即使向它們傳nil也不會(huì)報(bào)錯(cuò)脖祈。
* 現(xiàn)存代碼在和Swift混編時(shí),Swift編譯器會(huì)對(duì)當(dāng)前不安全的行為提出警告刷晋。
* nonnull不會(huì)影響性能盖高。并且在運(yùn)行時(shí),你仍然可以檢查被標(biāo)記為nonnull的參數(shù)是否為nil眼虱。在向后兼容時(shí)這可能是必要的喻奥。
一般你可以把nullable和nonnull簡(jiǎn)單的看成異常或斷言一樣捏悬,控制程序錯(cuò)誤撞蚕。特別當(dāng)返回類型為non-nullable時(shí)不能返回nil,除非為了向后兼容过牙。
在Xcode6.3發(fā)布了關(guān)鍵字__nullable和__nonnull甥厦。由于和第三方庫(kù)有潛在沖突,在Xcode7修改為_Nullable和_Nonnull 寇钉。為了兼容Xcode6.3矫渔,要預(yù)先定義宏__nullable和__nonnull來擴(kuò)展同樣的名字。
Back to Swift
現(xiàn)在添加Nullability Annotations到Objective-C的頭文件中摧莽,在Swift代碼中:
添加注釋之前:
class AAPLList : NSObject, NSCoding, NSCopying {
// ...
func itemWithName(name: String!) -> AAPLListItem!
func indexOfItem(item: AAPLListItem!) -> Int
@NSCopying var name: String! { get set }
@NSCopying var allItems: [AnyObject]! { get }
// ...
}
之后:
class AAPLList : NSObject, NSCoding, NSCopying {
// ...
func itemWithName(name: String) -> AAPLListItem?
func indexOfItem(item: AAPLListItem) -> Int
@NSCopying var name: String? { get set }
@NSCopying var allItems: [AnyObject] { get }
// ...
}
Swift代碼現(xiàn)在變得更加簡(jiǎn)潔。這只是一個(gè)微小的改變顿痪,但在使用時(shí)會(huì)變得更加方便镊辕。
哪里有問題提出修改意見~