自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

全世界都在說Swift開源的時候—2015 Objective-C 新特性

移動開發(fā) iOS 開發(fā)工具
自 WWDC 2015 推出和開源 Swift 2.0 后,大家對 Swift 的熱情又一次高漲起來,在羨慕創(chuàng)業(yè)公司的朋友們大談 Swift 新特性的同時,也有很多像我一樣工作上依然需要堅(jiān)守著 Objective-C 語言的開發(fā)者們。

Overview

自 WWDC 2015 推出和開源 Swift 2.0 后,大家對 Swift 的熱情又一次高漲起來,在羨慕創(chuàng)業(yè)公司的朋友們大談 Swift 新特性的同時,也有很多像我一樣工作上依然需要堅(jiān)守著 Objective-C 語言的開發(fā)者們。今年的 WWDC 中介紹了幾個 Objective-C 語言的新特性,還是在“與 Swift 協(xié)同工作”這種 Topic 里講的,越發(fā)凸顯這門語言的邊緣化了,不過有新特性還是極好的,接下來,本文將介紹下面三個主要的新特性:

Nullability

Lightweight Generics *

__kindof

Nullability

然而 Nullability 并不算新特性了,從上一個版本的 llvm 6.1 (Xcode 6.3) 就已經(jīng)支持。這個簡版的 Optional ,沒有 Swift 中 ? 和 ! 語法糖的支持,在 Objective-C 中就顯得非常啰嗦了:

  1. @property (nonatomic, strong, nonnull) Sark *sark; 
  2. @property (nonatomic, copy, readonly, nullable) NSArray *friends; 
  3. + (nullable NSString *)friendWithName:(nonnull NSString *)name; 

假如用來修飾一個變量,前面還要加雙下劃線,放到 block 里面就更加詭異,比如一個 Request 的 start 方法可以寫成:

  1. - (void)startWithCompletionBlock:(nullable void (^)(NSError * __nullable error))block; 

除了這倆外,還有個 null_resettable 來表示 setter nullable,但是 getter nonnull,繞死了,最直觀例子就是 UIViewController 中的 view 屬性:

  1. @property (null_resettable, nonatomic, strong) UIView *view; 

它可以被設(shè)成 nil,但是調(diào)用 getter 時會觸發(fā) -loadView 從而創(chuàng)建并返回一個非 nil 的 view。

從 iOS9 SDK 中可以發(fā)現(xiàn),頭文件中所有 API 都已經(jīng)增加了 Nullability 相關(guān)修飾符,想了解這個特性的用法,翻幾個系統(tǒng)頭文件就差不離了。接口中 nullable 的是少數(shù),所以為了防止寫一大堆 nonnull,F(xiàn)oundation 還提供了一對兒宏,包在里面的對象默認(rèn)加 nonnull 修飾符,只需要把 nullable 的指出來就行,黑話叫 Audited Regions:

  1. NS_ASSUME_NONNULL_BEGIN 
  2. @interface Sark : NSObject 
  3. @property (nonatomic, copy, nullable) NSString *workingCompany; 
  4. @property (nonatomic, copy) NSArray *friends; 
  5. - (nullable NSString *)gayFriend; 
  6. @end 
  7. NS_ASSUME_NONNULL_END 

Nullability 在編譯器層面提供了空值的類型檢查,在類型不符時給出 warning,方便開發(fā)者第一時間發(fā)現(xiàn)潛在問題。不過我想更大的意義在于能夠更加清楚的描述接口,是主調(diào)者和被調(diào)者間的一個協(xié)議,比多少句文檔描述都來得清晰,打個比方:

  1. + (nullable instancetype)URLWithString:(NSString *)URLString; 

NSURL 的這個 API 前面加了 nullable 后,更加顯式的指出了這個接口可能因?yàn)?URLString 的格式錯誤而創(chuàng)建失敗,使用時自然而然的就考慮到了判空處理。

不僅是屬性和方法中的對象,對于局部的對象、甚至 c 指針都可以用帶雙下劃線的修飾符,可以理解成能用 const 關(guān)鍵字的地方都能用 Nullability。

所以 Nullability 總的來說就是,寫著丑B,用著舒服 - -

Lightweight Generics

Lightweight Generics 輕量級泛型,輕量是因?yàn)檫@是個純編譯器的語法支持(llvm 7.0),和 Nullability 一樣,沒有借助任何 objc runtime 的升級,也就是說,這個新語法在 Xcode 7 上可以使用且完全向下兼容(更低的 iOS 版本)

帶泛型的容器

這無疑是本次最重大的改進(jìn),有了泛型后終于可以指定容器類中對象的類型了:

  1. NSArray<NSString *> *strings = @[@"sun", @"yuan"]; 
  2. NSDictionary<NSString *, NSNumber *> *mapping = @{@"a"@1, @"b"@2}; 

返回值的 id 被替換成具體的類型后,令人感動的代碼提示也出來了:

假如向泛型容器中加入錯誤的對象,編譯器會不開心的:

系統(tǒng)中常用的一系列容器類型都增加了泛型支持,甚至連 NSEnumerator 都支持了,這是非常 Nice 的改進(jìn)。和 Nullability 一樣,我認(rèn)為最大的意義還是豐富了接口描述信息,對比下面兩種寫法:

  1. @property (readonly) NSArray *imageURLs; 
  2. @property (readonly) NSArray<NSURL *> *imageURLs; 

不用多想就清楚下面的數(shù)組中存的是什么,避免了 NSString 和 NSURL 的混亂。

自定義泛型類

比起使用系統(tǒng)的泛型容器,更好玩的是自定義一個泛型類,目前這里還沒什么文檔,但攔不住我們寫測試代碼,假設(shè)我們要自定義一個 Stack 容器類:

  1. @interface Stack<ObjectType> : NSObject 
  2. - (void)pushObject:(ObjectType)object; 
  3. - (ObjectType)popObject; 
  4. @property (nonatomic, readonly) NSArray<ObjectType> *allObjects; 
  5. @end 

這個 ObjectType 是傳入類型的 placeholder,它只能在 @interface 上定義(類聲明、類擴(kuò)展、Category),如果你喜歡用 T 表示也 ok,這個類型在 @interface 和 @end 區(qū)間的作用域有效,可以把它作為入?yún)ⅰ⒊鰠?、甚至?nèi)部 NSArray 屬性的泛型類型,應(yīng)該說一切都是符合預(yù)期的。我們還可以給 ObjectType 增加類型限制,比如:

  1. // 只接受 NSNumber * 的泛型 
  2. @interface Stack<ObjectType: NSNumber *> : NSObject 
  3. // 只接受滿足 NSCopying 協(xié)議的泛型 
  4. @interface Stack<ObjectType: id<NSCopying>> : NSObject 

若什么都不加,表示接受任意類型 ( id );當(dāng)類型不滿足時編譯器將產(chǎn)生 error。

實(shí)例化一個 Stack,一切工作正常:

對于多參數(shù)的泛型,用逗號隔開,其他都一樣,可以參考 NSDictionary 的頭文件。

協(xié)變性和逆變性

當(dāng)類支持泛型后,它們的 Type 發(fā)生了變化,比如下面三個對象看上去都是 Stack,但實(shí)際上屬于三個 Type:

  1. Stack *stack; // Stack * 
  2. Stack<NSString *> *stringStack; // Stack<NSString *> 
  3. Stack<NSMutableString *> *mutableStringStack; // Stack<NSMutableString *> 

當(dāng)其中兩種類型做類型轉(zhuǎn)化時,編譯器需要知道哪些轉(zhuǎn)化是允許的,哪些是禁止的,比如,默認(rèn)情況下:

我們可以看到,不指定泛型類型的 Stack 可以和任意泛型類型轉(zhuǎn)化,但指定了泛型類型后,兩個不同類型間是不可以強(qiáng)轉(zhuǎn)的,假如你希望主動控制轉(zhuǎn)化關(guān)系,就需要使用泛型的協(xié)變性和逆變性修飾符了:

__covariant - 協(xié)變性,子類型可以強(qiáng)轉(zhuǎn)到父類型(里氏替換原則)

__contravariant - 逆變性,父類型可以強(qiáng)轉(zhuǎn)到子類型(WTF?)

協(xié)變:

  1. @interface Stack<__covariant ObjectType> : NSObject 

效果:

逆變:

  1. @interface Stack<__contravariant ObjectType> : NSObject 

效果:

協(xié)變是非常好理解的,像 NSArray 的泛型就用了協(xié)變的修飾符,而逆變我還沒有想到有什么實(shí)際的使用場景。

__kindof

__kindof 這修飾符還是很實(shí)用的,解決了一個長期以來的小痛點(diǎn),拿原來的 UITableView 的這個方法來說:

  1. - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier; 

使用時前面基本會使用 UITableViewCell 子類型的指針來接收返回值,所以這個 API 為了讓開發(fā)者不必每次都蛋疼的寫顯式強(qiáng)轉(zhuǎn),把返回值定義成了 id 類型,而這個 API 實(shí)際上的意思是返回一個 UITableViewCell 或 UITableViewCell 子類的實(shí)例,于是新的 __kindof 關(guān)鍵字解決了這個問題:

  1. - (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier; 

既明確表明了返回值,又讓使用者不必寫強(qiáng)轉(zhuǎn)。再舉個帶泛型的例子,UIView 的 subviews 屬性被修改成了:

  1. @property (nonatomic, readonly, copy) NSArray<__kindof UIView *> *subviews; 

這樣,寫下面的代碼時就沒有任何警告了:

  1. UIButton *button = view.subviews.lastObject; 

Where to go

有了上面介紹的這些新特性以及如 instancetype 這樣的歷史更新,Objective-C 這門古老語言的類型檢測和類型推斷終于有所長進(jìn),現(xiàn)在不論是接口還是代碼中的 id 類型都越來越少,更多潛在的類型錯誤可以被編譯器的靜態(tài)檢查發(fā)現(xiàn)。

同時,個人感覺新版的 Xcode 對繼承鏈構(gòu)造器的檢測也加強(qiáng)了,NS_DESIGNATED_INITIALIZER 這個宏并不是新面孔,可以使用它標(biāo)志出像 Swift 一樣的指定構(gòu)造器和便捷構(gòu)造器。

最后,附上一段用上了所有新特性的代碼,Swift 是發(fā)展趨勢,如果你暫時依然要寫 Objective-C 代碼,把所有新特性都用上,或許能讓你到新語言的遷移更無痛一點(diǎn)。

責(zé)任編輯:chenqingxiang 來源: sunnyxx
相關(guān)推薦

2015-11-02 10:13:41

iOSObjective-C語法

2014-11-25 10:18:17

Objective-C

2014-07-01 09:22:01

SwiftObjective-CiOS

2013-07-24 19:19:03

Objective-CiOS開發(fā)動態(tài)特性之protoc

2015-06-08 10:02:40

swiftOC兼容

2014-08-05 13:09:34

Objective-C動態(tài)特性

2014-09-24 11:15:05

Objective-CSwift

2014-09-26 09:49:48

SwiftObjective-C

2014-06-05 13:54:03

SwiftiOSObjective-C

2020-03-02 15:48:26

戴爾

2017-04-07 16:00:59

SwiftObjective-CFramework

2014-12-12 14:57:11

Objective-C封裝

2014-10-13 09:54:08

Objective-CSwift

2011-08-04 13:55:10

Cocoa Objective- 文件

2011-08-10 18:07:29

Objective-C反射

2011-05-11 11:20:26

Objective-C

2011-05-11 15:58:34

Objective-C

2013-06-20 10:40:32

Objective-C實(shí)現(xiàn)截圖

2013-03-27 12:54:00

iOS開發(fā)Objective-C

2015-07-08 10:47:57

Using Swift CocoaObjective-C
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號