學習objc時,尤爲是先學過其餘編程語言再來看objc時,總會對objc的類聲明的關鍵字interface
感到有點奇怪,在其它面向對象的語言中一般由class
關鍵字來表示,而interface
在java中表示的卻大約至關於objc的protocol
,這個關鍵字的區別究竟表明了objc語言的設計者怎樣的思想呢,在objc類設計中須要注意哪些問題呢?接下來對這個問題進行一些思考和探究.java
先來段Wiki:c++
In object-oriented programming, a protocol or interface is a common means for unrelated objects to communicate with each other. These are definitions of methods and values which the objects agree upon in order to cooperate.git
接口約定了對象間交互的屬性和方法,使得對象間無需瞭解對方就能夠協做。
說的洋氣點就是解耦
嘛,細心點也能發現Wiki中interface
和protocol
表示了相近的語義。
引用我和項目組架構師討論有關interface的問題時他的說法:github
interface就是一個object定義的能夠被外界影響的方式編程
說着他指了下旁邊桌子上放着的一把傘,說,這把傘我能夠打開它,打開這個動做就是它的一個interface,桌子旁邊還放着一個盒子,雖然它和傘都放在這張桌子上,可是它們之間永遠不會互相影響,因此:微信
interface只存在於能互相影響的二者間架構
學習objc時最先接觸的就是怎麼寫一個類了,從.h
中寫@interface
聲明類,再從.m
中寫@implementation
實現方法,因此,objc中寫一個@interface
就至關於c++中寫一個class
。但這是真的麼?app
寫個小test驗證一下:
有兩個類,Sark
和Dark
,Sark
類只有.m
文件,其中只寫@implementation
;Dark
類只有.h
頭文件,其中只寫@interface
,而後以下測試代碼:編程語言
1 |
Class sarkClass = NSClassFromString(@"Sark"); |
NSClassFromString
方法調用了runtime方法,根據類名將加載進runtime的這個類找出來,沒有這個類就回返回空(Nil)。
結果是sarkClass
存在,而darkClass
爲空,說明什麼?是否說明其實@implementation
纔是真正的Class?
進一步,不止能取到這個沒有@interface的類,還能夠正常調用方法(由於萬能的runtime)ide
以下面的測試代碼:
1 |
Sark *sark = [Sark new]; |
要是沒有@interface
的聲明,類名,方法名都會報錯說找不到,可是能夠像下面同樣繞一下:
1 |
Class cls = NSClassFromString(@"Sark"); |
其實,從rewrite
後的objc代碼能夠發現,對於消息的發送,偏偏就是會被處理成相似上面的代碼,使用字符串mapping出Class
,selctor
等再使用objc_msgSend()
進行函數調用,以下面所示:
1 |
// 通過clang -rewrite-objc 命令重寫後的代碼 |
@interface
咱們幹過的事:
@implementation
咱們幹過的和能夠乾的事:
在@implementation
幹一些事情用的相對較少,可是是徹底合法的,如這樣用:
1 |
@implementation Sark : NSObject { |
經過對比能夠發現,@interface對objc類結構的合成並沒有決定性做用,加上無決定性是由於若是沒有@interface
會丟失一些類自省的原始數據,如屬性列表和協議列表,但對於純粹的對象消息發送並沒有影響。
因此說,能夠得出這麼一個結論,objc中@interface就是爲了給調用者看的,是和調用者的一個protocol,沒錯,就是protocol。
與其把@implementation
扯進來不如對比下@protocol
我理解objc的@interface
和@protocal
間惟一的區別就是是否和一個類型綁定,這讓我想起來鴨子類型
(Duck typing), wiki連接
「當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就能夠被稱爲鴨子。」
Duck type在objc的體現無疑就是@protocol
了,咱們經常使用id<XXXDelegate> delegate
的方式聲明一個delegate,咱們無需care這貨究竟是什麼類型,咱們只知道他能幹什麼就能夠work了。一樣的功能我也可使用XXXDelegate *delegate
的方式來定義,只不過這樣的話這個類又須要耦合一個XXXDelegate
類型,而這個delegate類是它本來並不須要關心的。
因此說,@interface
是@protocol
的強類型升級版。
舉個NSObject
的栗子最合適:
1 |
@interface NSObject <NSObject> { |
NSObject之因此成爲NSObject,絕大多數都是<NSObject>
協議定義的方法,實體類@interface定義的惟一一個變量isa
指針,爲了繼承鏈和消息傳遞。
除了<NSObject>
協議外,NSObject還有不少Category來補充它的功能,其實仔細想一想,Category更像protocol,一個補充協議
,一樣不能添加實例變量,可是和@interface
同樣須要與Class綁定。
進一步來說,自從屬性能自動合成變量以後,在頭文件@interface
中寫大括號聲明實例變量的狀況愈來愈少(能夠參見近幾個版本iOS SDK中類頭文件裏這種寫法幾乎消失),所以,@interface
和@protocol
的差異進一步縮小。
我喜歡將Class
和interface
的關係比喻成電視+遙控器
,那麼objc中的消息機制就能夠理解成:
用戶(caller)經過遙控器(interface)上的按鈕(methods)發送紅外線(message)來操縱電視(object)
因此,有沒有遙控器,電視都在那兒,也就是說,有沒有interface,class都是存在的,只是這種存在並無意義,就好像這個電視沒人會打開,沒人會用,沒人能看,一堆廢鐵擺在那兒。
對比簡潔的遙控器,一個擁有不少按鈕的老式電視遙控器,咱們常常會用到的按鈕能有幾個呢?
因此,在設計一個類的interface的時候,如同在設計遙控器應該有怎樣功能的按鈕,要從調用者的角度出發,區分邊界,應該時刻有如下幾點考慮:
.h
中(而不是放在.m
的類擴展中)麼?看過很多代碼,從@interface設計上多少就能看出做者的水平,分享下我對於這個問題的一些拙見。
好比,有以下一個類(這個類無心義,主要關注寫法):
1 |
// Sark.h |
這個interface出現的問題:
<NSXMLParserDelegate>
不該該在頭文件@interface中聲明,而應該在類擴展中聲明;公開由外部調用的協議,如<NSCopying>
則寫在這兒是正確的。實例變量
和IBOutlet
不該出如今這兒定義,這將類的內部實現暴露了出去,自從屬性能夠自動合成後,這裏就更應該清淨了。使用這個類或者對其進行修改時,通常都是從功能上找,因此把同一功能模塊的一組屬性或方法寫在一塊
Category
分塊類擴展
將interface按功能分區Category
裏不能添加實例變量,可是類擴展能夠,通常都在.m
中做爲私有interface使用,一樣在頭文件裏做爲分區使用,如,ReactiveCocoa中的RACStream.h
首先,類實現內部.m文件中使用的其餘interface應該在.m文件import,若是也寫在header中就會形成對調用者的污染;當interface中出現其餘Class
或protocol
時,可使用前置聲明@class XXX
, @protocol XXX
;當模塊(一組類)內部間須要有一些定義(如常量、類型)而又不須要模塊使用者知道時,使用一個內部頭文件在模塊中使用。
考慮調用者的使用方即是很必要的,過火了反而增長了複雜度:
1 |
@interface Sark : NSObject |
提供了一組這樣的方法,調用者可能只能用到其中的一個,那這樣倒不如只留一個接口。
單例模式當然好用,但感受有點過分,將接口設計成單例入口前須要考慮一下:
感謝@像條狗在飛
在留言中提出的問題,問題大概能夠總結爲:當子類須要使用父類的一個私有屬性(方法)時,須要把這個屬性(方法)放到父類的header中,但暴露給子類的同時暴露給了外部調用者,如何解決?
個人方案是:創建一個私有header
,使用類擴展
定義父類須要暴露給子類的屬性(方法),而後在各自的.m
文件中引用,如:
有Father類和Son類,繼承關係,能夠考慮建一個如FatherPrivate.h
的私有header:
1 |
// FatherPrivate.h |
同時在Father.m和Son.m中同時import這個私有header,這樣,Father和Son內部對於定義的屬性和方法都是透明的,而對外部是隱藏的(由於兩個類的header中都沒有import這個私有header)
@implementation
合成了Class,而非@interface
,@interface
是@protocol
的強類型升級版,它們和Category
都表示了相近的含義最少知識原則
@interface
自己就是最好的文檔http://en.m.wikipedia.org/wiki/Interface_(object-oriented_programming)
http://zh.wikipedia.org/wiki/%E9%B8%AD%E5%AD%90%E7%B1%BB%E5%9E%8B
原創文章,轉載請註明源地址,blog.sunnyxx.com
原創文章,轉載請註明原地址:blog.sunnyxx.com
對博主有意思?新浪微博@我就叫Sunny怎麼了
or 微信搜索訂閱號sunnyxx或掃下面的逗比狗