Objective-C 的現(xiàn)代語(yǔ)法以及新特性
Swift的確是一個(gè)很強(qiáng)大的語(yǔ)言,各種特性使用起來(lái)非常簡(jiǎn)潔強(qiáng)大,但是目前來(lái)說,感覺成熟度還是不夠,所以商業(yè)項(xiàng)目中使用OC來(lái)說是比較穩(wěn)健的行為??磥?lái)一下WWDC 2015的 Swift and Objective-C Interoperability session,視頻前半部分主要是講解swift和OC之間的交互的規(guī)則,后面則講到OC的一部分新的語(yǔ)言特性,這幾個(gè)特性,Apple的開發(fā)人員在WWDC上說的那樣,對(duì)代碼的可讀性提升非常大,所以從swift中把這個(gè)特性引入到OC中,個(gè)人感覺也是為后續(xù)向swift的遷移提供支撐,最主要的是這些特性在iOS SDK中以及全面采用并且兼容低版本,所以可以在當(dāng)前工作中引入這些特性。
文章的前半部分記錄一些之前的OC的現(xiàn)代語(yǔ)法,后面講解WWDC 2015中介紹的新特性,詳細(xì)建議去觀看WWDC 2015的視頻。
instancetype
這個(gè)方面可以參考我之前總結(jié)的一篇博客,關(guān)于 id、NSObject *、id、instancetype的區(qū)別 : http://blog.csdn.net/colorapp/article/details/45317347
Properties
使用Properties來(lái)代替實(shí)例變量有很多優(yōu)勢(shì):
Auto synthesized getters and setters. 使用@property聲明的屬性能自動(dòng)生成getter與setter方法。
Better declaration of intent of a set of methods. 比為屬性聲明一系列方法代碼上要清晰很多。
Property keywords that express additional information about behavior. Property使用其他的一些關(guān)鍵子可以表達(dá)一些實(shí)例變量無(wú)法表達(dá)的信息,比如 assign, weak, atomic等等。
Property方法有一個(gè)非常簡(jiǎn)明的命名規(guī)范,getter方法的名稱是property的名稱,setter方法的名稱是在property名稱之前添加set前綴(駝峰法)。通過還可以通過getter關(guān)鍵字指定getter的名稱。
在聲明一個(gè)Property的時(shí)候,需要記住下面這些不能是properties的:
init method
copy method, mutableCopy method
A class factory method
初始化一個(gè)action并返回一個(gè)BOOL結(jié)果的方法
A method that explicitly changes internal state as a side effect of a getter
Enumration Marcos
使用NS_ENUM來(lái)定義枚舉,使用NS_OPTIONS來(lái)定義options。這兩個(gè)宏可以改善Xcode中的代碼補(bǔ)全,明確指出枚舉和options的類型和大小。
Object Initialization
可能是為了兼容swift,OC中添加了 designated initializer 初始化方法和 convenience initializers 初始化方法:
designated initializer : 負(fù)責(zé)調(diào)用superclass的初始化方法以及初始化自己的實(shí)例變量的初始化方法
convenience initializers : 非designated initializer都被稱為designated initializer。這些initializer內(nèi)部實(shí)現(xiàn)一般都是調(diào)用另外一個(gè)initializer,然而最終一系列鏈?zhǔn)秸{(diào)用之后,最終都會(huì)調(diào)用某一個(gè)designated initializer 方法來(lái)進(jìn)行初始化行為。
實(shí)現(xiàn)一個(gè)designated initializer方法很簡(jiǎn)單,通過NS_DESIGNATED_INITIALIZER宏即可實(shí)現(xiàn),但是使用designated initializer的時(shí)候,會(huì)有一些限制規(guī)則,跟swift中的這些規(guī)則非常類似。詳情可以參考:https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html
WWDC 2015
Nullability
Nullability特性用來(lái)指明 Objective-C/C 指針是否可以為nil。顯然,使用這個(gè)特性更能清晰表達(dá)API的意圖,同時(shí)可以提升編譯器的static checking,還有一點(diǎn)就可以提高這些API在swift中的可用性。如果使用Xcode 7的話,可能注意到在iOS SDK中這個(gè)特性已經(jīng)被大量采用了。下面這種截圖說明了Nullability的用法。
OC是如何引入這個(gè)特性,并且又讓低版本的iOS支持的呢?Apple稱之為 Audited Regions,也就是下面這兩個(gè)宏之間的區(qū)域,NS_ASSUME_NONNULL_BEGIN … NS_ASSUME_NONNULL_END。
Audited Regions對(duì)其中的指針做了一些默認(rèn)的假設(shè),Single-level指針被認(rèn)為是nonnull的,NSError**指針被認(rèn)為在各個(gè)指針level上面都是nullable的。所以我們?cè)贏udited Regions內(nèi)只需要指明那些 nullable 或者 null_unspecified的場(chǎng)景。
在C指針中使用 Nullability 的話,與OC中不同的地方在于,使用的nullability qualifier需要在前面添加雙下劃線,并且要將nullability qualifier寫在指針后面。例如下面:
Lightweight Generics
這個(gè)輕量級(jí)泛型,一方面會(huì)提高代碼可讀性,讓API變得更加清晰。另外一方面,還能使編譯器會(huì)幫助我們做一些類型檢查,找到一些潛在的錯(cuò)誤,達(dá)到 Type Safety的效果。
日常主要的用法是針對(duì)兩個(gè)集合類的,NSArray與NSDictionary,詳細(xì)用法可以參考官方SDK中的使用。同時(shí),我們也可以在我們自己的代碼來(lái)使用這個(gè)輕量級(jí)泛型,在自定義類,category,extension等等。
自定義類中的使用語(yǔ)法:
Category / Extension的使用語(yǔ)法:
WWDC中還強(qiáng)調(diào)了一點(diǎn)是,Lightweight Generics 是向前兼容的,不會(huì)更改OC的runtime,同時(shí)也不會(huì)對(duì)生成的代碼造成任何影響。
__kindof
在OC中,我們的代碼中會(huì)大量使用id這個(gè)特性,這個(gè)特性用起來(lái)會(huì)帶來(lái)很多很方便的特性,但是它有個(gè)缺陷,我們經(jīng)常需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。Xcode 7中有個(gè)新特性,__kindof,“Kindof” types express “some kind of X”,用__kind修飾的變量表示是某個(gè)類或者這個(gè)類的子類。
當(dāng)我們把這個(gè)類或者子類的其他變量賦值給這個(gè)變量時(shí),編譯器會(huì)默認(rèn)幫我們進(jìn)行類型轉(zhuǎn)換以及類型檢查工作,這樣就不需要我們寫一些強(qiáng)制類型轉(zhuǎn)換這樣的代碼了。最簡(jiǎn)單的一個(gè)例子是在UITableView的應(yīng)用,cellForRowAtIndexPath:返回的變量使用這個(gè)修飾之后,我們就不再需要寫任何強(qiáng)制類型轉(zhuǎn)換了,例如,CustomCell *cell = [tableview cellForRowAtIndexPath:indexPath];
同時(shí),我們可以將Kindof types和lightweight generics結(jié)合在一起,比如官方提供的特性:
關(guān)于id類型
看了上面這些新特性之后,你會(huì)發(fā)現(xiàn)在平時(shí)開發(fā)中,你真的還需要那么多id嗎?大多數(shù)情況下,我們都可以使用一個(gè)更加精確的類型表示,這樣能避免一些例如 type safety的問題,同時(shí)也能讓代碼更加清晰。下面看一下官方指明的替代id的情景:
在返回 “self” 的方法中,使用instancetype來(lái)代替id
大多數(shù) Collections 都可以變成 Typed Collections 來(lái)代替id
__kindof X * 來(lái)表示 “some subclass of X”,而不再使用id,可以減少類型強(qiáng)制轉(zhuǎn)換之類的代碼
id表示conforms to SomeProtocol的任意類型
那什么情況下使用id呢?只有那些你確認(rèn)要表示”an object of any type”的時(shí)候再使用id,否則,盡量使用其他語(yǔ)法代替id。
References
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html
https://developer.apple.com/videos/play/wwdc2015-401/
http://blog.sunnyxx.com/2015/06/12/objc-new-features-in-2015/