日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
全世界都在說(shuō)Swift開(kāi)源的時(shí)候—2015Objective-C新特性

Overview

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

Nullability

Lightweight Generics *

__kindof

Nullability

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

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

假如用來(lái)修飾一個(gè)變量,前面還要加雙下劃線(xiàn),放到 block 里面就更加詭異,比如一個(gè) Request 的 start 方法可以寫(xiě)成:

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

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

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

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

從 iOS9 SDK 中可以發(fā)現(xiàn),頭文件中所有 API 都已經(jīng)增加了 Nullability 相關(guān)修飾符,想了解這個(gè)特性的用法,翻幾個(gè)系統(tǒng)頭文件就差不離了。接口中 nullable 的是少數(shù),所以為了防止寫(xiě)一大堆 nonnull,F(xiàn)oundation 還提供了一對(duì)兒宏,包在里面的對(duì)象默認(rèn)加 nonnull 修飾符,只需要把 nullable 的指出來(lái)就行,黑話(huà)叫 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 在編譯器層面提供了空值的類(lèi)型檢查,在類(lèi)型不符時(shí)給出 warning,方便開(kāi)發(fā)者第一時(shí)間發(fā)現(xiàn)潛在問(wèn)題。不過(guò)我想更大的意義在于能夠更加清楚的描述接口,是主調(diào)者和被調(diào)者間的一個(gè)協(xié)議,比多少句文檔描述都來(lái)得清晰,打個(gè)比方:

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

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

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

所以 Nullability 總的來(lái)說(shuō)就是,寫(xiě)著丑B,用著舒服 - -

Lightweight Generics

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

帶泛型的容器

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

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

返回值的 id 被替換成具體的類(lèi)型后,令人感動(dòng)的代碼提示也出來(lái)了:

假如向泛型容器中加入錯(cuò)誤的對(duì)象,編譯器會(huì)不開(kāi)心的:

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

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

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

自定義泛型類(lèi)

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

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

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

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

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

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

對(duì)于多參數(shù)的泛型,用逗號(hào)隔開(kāi),其他都一樣,可以參考 NSDictionary 的頭文件。

協(xié)變性和逆變性

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

 
 
  1. Stack *stack; // Stack * 
  2. Stack *stringStack; // Stack 
  3. Stack *mutableStringStack; // Stack 

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

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

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

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

協(xié)變:

 
 
  1. @interface Stack<__covariant ObjectType> : NSObject 

效果:

逆變:

 
 
  1. @interface Stack<__contravariant ObjectType> : NSObject 

效果:

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

__kindof

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

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

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

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

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

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

這樣,寫(xiě)下面的代碼時(shí)就沒(méi)有任何警告了:

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

Where to go

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

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

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


網(wǎng)站名稱(chēng):全世界都在說(shuō)Swift開(kāi)源的時(shí)候—2015Objective-C新特性
文章起源:http://www.5511xx.com/article/dhsseip.html