在iOS開發(fā)中,框架 > 在你的代碼中引入框架

2012-05-25 09:28:11來源:果迷網(wǎng)作者:

在開發(fā) iOS 和 Mac OS X 應(yīng)用時(shí),你并非是全部由自己從頭做起。你的工作是基于蘋果公司創(chuàng)建和收集的 Objective-C 框架基礎(chǔ)之上的?蚣芫褪且粋(gè)類庫,在運(yùn)行時(shí)可以被多個(gè)進(jìn)程共用;框架里還包括支持軟件開發(fā)用的資源

在開發(fā) iOS 和 Mac OS X 應(yīng)用時(shí),你并非是全部由自己從頭做起。你的工作是基于蘋果公司創(chuàng)建和收集的 Objective-C 框架基礎(chǔ)之上的?蚣芫褪且粋(gè)類庫,在運(yùn)行時(shí)可以被多個(gè)進(jìn)程共用;框架里還包括支持軟件開發(fā)用的資源文件。Cocoa Touch 和 Cocoa 框架為你帶來了一套相互支撐的類,它們共同構(gòu)成你應(yīng)用的一部分,通常是最重要的那一部分。

利用 C 語言的函數(shù)庫,你可以根據(jù)所編寫的應(yīng)用種類隨意選擇所需函數(shù)并調(diào)用它們。而框架則不同,它是將你的程序限定在一個(gè)設(shè)計(jì)范圍之內(nèi),至少是限定在根據(jù)你的應(yīng)用的作用而定的一個(gè)范圍內(nèi)。當(dāng)使用面向?qū)ο罂蚣軙r(shí),程序的大部分工作都可以通過調(diào)用框架里面類的方法來完成,這和面向過程編程類似。但是你仍然需要對一般框架行為進(jìn)行自定義,通過實(shí)現(xiàn)若干方法讓它們能夠在適當(dāng)?shù)臅r(shí)間被調(diào)用。這些方法就是將你的代碼與框架事先設(shè)定的結(jié)構(gòu)相連接的鉤子,為其添加更加適合你的應(yīng)用的獨(dú)特行為方式。

下邊的內(nèi)容將帶你探尋框架代碼和應(yīng)用代碼之間的關(guān)系。

應(yīng)用的驅(qū)動(dòng)力是「事件」

要探尋在你的代碼和框架代碼之間的關(guān)系,首先可以思考一下當(dāng)應(yīng)用啟動(dòng)時(shí)究竟發(fā)生了什么。最基本的事情是,應(yīng)用建立好一組核心對象,然后把控制權(quán)交給那些對象。隨著程序的運(yùn)行會(huì)產(chǎn)生越來越多的對象,但是在最初階段最需要的東西是完整的結(jié)構(gòu),要有足夠數(shù)量的核心代碼網(wǎng)絡(luò)來處理初始任務(wù)。最基本的任務(wù)一共由兩種:

  • 繪制應(yīng)用的初始用戶界面。
  • 當(dāng)用戶和用戶界面產(chǎn)生交互時(shí),處理接收到的事件。

在初始用戶界面顯示在屏幕上之后,應(yīng)用就由內(nèi)部的事件所驅(qū)動(dòng)。其中最重要的事件是來自用戶的操作,比如點(diǎn)按按鈕。系統(tǒng)會(huì)向應(yīng)用報(bào)告這樣的事件,同時(shí)伴有它們各自的信息。同時(shí)含有你編寫的代碼以及框架代碼的應(yīng)用就會(huì)處理這些事件,并根據(jù)需要更新用戶界面。

應(yīng)用獲取事件并做出響應(yīng),一般的響應(yīng)是繪制用戶界面,然后等待下一個(gè)事件。只要用戶或者其他什么事件來源(比如計(jì)時(shí)器)在發(fā)出各種事件,應(yīng)有就會(huì)不停地、一個(gè)接一個(gè)地收到這些事件。在應(yīng)用運(yùn)行到退出期間,幾乎所有行動(dòng)都來自于用戶發(fā)出的事件。

獲取事件并做出響應(yīng)的這種機(jī)制叫做主事件循環(huán)。核心組里的一個(gè)對象,即全局應(yīng)用對象負(fù)責(zé)管理主事件循環(huán)。它會(huì)獲取事件,將事件派送到相應(yīng)對象或者最適合處理這種事件的對象,然后去獲取下一個(gè)事件。下圖反映了 iOS 系統(tǒng)中 Cocoa Touch 應(yīng)用的主事件循環(huán)過程。

\

使用 Objective-C 框架

Cocoa Touch 和 Cocoa 框架只不過是提供各類服務(wù)的各個(gè)類的收納袋。它們構(gòu)成了面向?qū)ο蟮目蚣,類的集合?gòu)建了一個(gè)問題空間,并為其提供了一個(gè)整合的解決方案。框架并非提供各種分散的服務(wù),在你需要時(shí)去利用(比如函數(shù)庫就是這樣),框架勾勒出并實(shí)現(xiàn)了整個(gè)應(yīng)用架構(gòu),你自己的代碼必須適應(yīng)這個(gè)架構(gòu)。由于應(yīng)用架構(gòu)是個(gè)大的一般類,因此你可以按照需要來定制自己的每一個(gè)應(yīng)用。在設(shè)計(jì)應(yīng)用時(shí),你并非向應(yīng)用插入一個(gè)函數(shù)庫,而是向框架提供設(shè)計(jì)的一般類插入你的代碼。

要使用框架,則必須接受其定義的應(yīng)用架構(gòu),并按照自己的需要使用和自定義框架里的類,并將自己的模子應(yīng)用到這個(gè)架構(gòu)上去?蚣苤械拿總(gè)類都互相依賴,成組出現(xiàn),而不是形單影只的分散體。起初,要讓自己的代碼適應(yīng)框架的架構(gòu)看上去很受限制,但事實(shí)卻正好相反。框架能夠讓你用無數(shù)種方法變換和擴(kuò)展其設(shè)定的一般類行為。你唯一要做的就是接受的條件就是所有應(yīng)用行為都要在同一個(gè)基礎(chǔ)之上,因?yàn)樗鼈兌蓟谕粋(gè)架構(gòu)。舉一個(gè)較為寬泛的例子,Objective-C 框架就好比一座房屋的骨架,你的應(yīng)用代碼就是門、窗、墻壁以及一切使這棟房子變得獨(dú)特的元素。

\

從使用和整合框架到自己代碼的角度來看,總共有兩種類:

  • 復(fù)活對象。有些類定義了復(fù)活(Off-the-shelf)對象,也就是可以直接拿來使用的對象。你只需要?jiǎng)?chuàng)建該類的實(shí)例,并按照自己的需要使用該實(shí)例即可。
  • 一般對象。使用一般框架中的類時(shí),你可以創(chuàng)建它們的子類并重寫部分所需方法的實(shí)現(xiàn)(有時(shí)甚至必須創(chuàng)建子類并重寫)。通過創(chuàng)建它們的子類,你就可以將自己的代碼引入應(yīng)用的架構(gòu)中了?蚣軙(huì)在合適的時(shí)機(jī)調(diào)用你創(chuàng)建的子類中的方法。

為一般類框架創(chuàng)建子類是將自己編寫的程序代碼整合到框架提供的架構(gòu)中去的一項(xiàng)主要技術(shù),但并不是唯一的方式。在后邊的文章中你會(huì)學(xué)到,Cocoa Touch 和 Cocoa 框架還含有一些結(jié)構(gòu)和機(jī)制,可以讓你自定的對象和框架對象更好地協(xié)同工作。

當(dāng)你建立子類時(shí),一般需要事先決定好兩件事:從哪個(gè)類繼承(即父類),以及要重寫該類的哪些方法。下文將著重探索如何做這兩個(gè)決定。

從 Cocoa 或 Cocoa Touch 框架繼承

像 UIKit 這樣的框架定義了一種可供多種應(yīng)用利用的架構(gòu),因?yàn)樗莻(gè)一般類。正因?yàn)榇耍阍诳吹侥承┛蚣艿念愂殖橄蟛⑶矣幸獗3植煌暾麜r(shí)也不必驚訝。這樣的類通常實(shí)現(xiàn)了若干段通用代碼,但是會(huì)留下明顯未完成或沒有寫成安全默認(rèn)樣式的部分代碼。

要為應(yīng)用添加特定的行為,最主要的做法就是給框架類創(chuàng)建自定義子類。子類為父類提供其缺少的內(nèi)容,填補(bǔ)了父類在應(yīng)用中存在的一些溝壑。你創(chuàng)建的自定義子類的實(shí)例會(huì)出現(xiàn)在框架定義的對象網(wǎng)絡(luò)中,并且從框架中繼承與其他對象協(xié)同工作的能力。要讓一個(gè)應(yīng)用變得有用處,它至少要包含一個(gè)子類,或許更多。

接下來的部分將討論和探索關(guān)于創(chuàng)建、使用子類的一些決策和謀略,和它們的基本需求。不過我們不會(huì)談到創(chuàng)建子類的具體細(xì)節(jié)!禩he Objective-C Programming Language》中的「定義一個(gè)類」章節(jié)講述了這些技術(shù)。

何時(shí)需要?jiǎng)?chuàng)建子類

創(chuàng)建和使用子類其實(shí)是對現(xiàn)有類的重復(fù)利用,并按照自己的需求定制它的過程。有時(shí)子類的全部職責(zé)就是重寫從父類中繼承而來的某個(gè)方法,將它進(jìn)行輕微的改動(dòng)。其他子類則可能向父類添加一兩個(gè)屬性(比如實(shí)例變量),然后讓定義的方法對這些屬性進(jìn)行操作,將它們整合到父類的行為當(dāng)中去。

創(chuàng)建和使用子類時(shí),首先要做的是確定父類框架。你在考慮時(shí)可以參考下邊的向?qū)В?/p>

  • 了解父類框架。你必須熟知框架中的每個(gè)類都帶有什么目的,以及能做哪些事情。閱讀開發(fā)者資源庫里的框架介紹和框架本身各個(gè)類的代碼就是個(gè)很好的開始。也許某個(gè)類早已實(shí)現(xiàn)了你想要做到的事情。如果你發(fā)現(xiàn)某個(gè)類基本能夠做到你需要的事情,也就意味著你很幸運(yùn),這個(gè)類就可以拿來當(dāng)作自定義子類的父類。比如,當(dāng)學(xué)習(xí)《你的第一個(gè) iOS 應(yīng)用》時(shí)就遇到過 UIViewController 等 UIKit 框架的類。要更深入地了解這些類,你可以這樣做:
    1. 在 Xcode 中,選擇 Window > Organizer。
    2. 點(diǎn)按工具欄里的 Documentation 按鈕。
    3. 點(diǎn)按導(dǎo)航區(qū)頂部的 Browse,開始瀏覽已經(jīng)安裝的開發(fā)者資源庫。
    4. 點(diǎn)按最近的 iOS 資源庫(你可能需要首先登錄到 Apple Developer 才可以)。iOS Developer Library 將在內(nèi)容區(qū)域里顯示出來。
    5. 在文檔列表上方的過濾選項(xiàng)里,輸入“UIKit Framework Reference”。篩選后的列表就只會(huì)顯示符合輸入內(nèi)容的文檔了。
    6. 點(diǎn)按一個(gè)文檔的名稱,其頁面就會(huì)顯示出來,包含 UIKit 的所有類、協(xié)議列表。
  • 仔細(xì)閱讀介紹,并點(diǎn)按列出的類和協(xié)議,這樣就能了解更多關(guān)于它們的知識(shí)。
  • 對自己的應(yīng)用將要做什么非常明確。這條建議既可以說是針對整個(gè)應(yīng)用的,也可以說是針對應(yīng)用中每個(gè)獨(dú)立功能的。某些框架的架構(gòu)中強(qiáng)制規(guī)定了自己的子類需要符合哪些要求。比如,如果你的應(yīng)用是基于文檔的,你就必須為抽象文檔類創(chuàng)建子類。
  • 定義你的子類產(chǎn)生的實(shí)例將要扮演的角色。在 iOS 和 Mac OS X 應(yīng)用開發(fā)中,模型-視圖-控制器(MVC)設(shè)計(jì)模式就是對象的三大角色。視圖對象會(huì)顯示在用戶界面上;模型對象則掌握用戶數(shù)據(jù)(并實(shí)現(xiàn)一定的數(shù)據(jù)處理算法);控制器對象則是連接視圖和模型對象的中間人。搞清楚各個(gè)對象的角色之后,決定使用哪個(gè)子類就會(huì)非常容易了。比如,當(dāng)你需要在 iOS 應(yīng)用中進(jìn)行一些自定義繪制時(shí),你就需要一個(gè) UIView 的子類,UIView 是 UIKit 框架中的基本視圖類。

雖然子類操作在 iOS 和 Mac OS X 編程中非常重要,但它并不永遠(yuǎn)都是解決問題的最好方法。如果你需要向某個(gè)類添加少量的便捷方法,你可以創(chuàng)建范疇類(Category), 而不是創(chuàng)建它的子類;蛘,當(dāng)你需要攔截應(yīng)用的某個(gè)特殊行為時(shí),你可以在設(shè)計(jì)模式的基礎(chǔ)上,選用框架中其他大量資源里的某一個(gè),比如委托(這些設(shè)計(jì)模式在《用設(shè)計(jì)模式讓應(yīng)用開發(fā)流水線化》一文中有詳細(xì)描述)。時(shí)刻牢記,有些框架的類是不可以用來創(chuàng)建子類的。參考文檔中會(huì)告訴你各個(gè)類是否能夠創(chuàng)建子類。

重寫一個(gè)方法

你可以創(chuàng)建一個(gè)子類但不實(shí)現(xiàn)任何父類的方法;比如說某個(gè)子類聲明了一些額外屬性并定義了訪問這些屬性的新方法,并在父類中調(diào)用這些方法。然而,有些子類的首要任務(wù)是實(shí)現(xiàn)一系列已由父類聲明的方法(或父類采用的某個(gè)協(xié)議里)。重新實(shí)現(xiàn)一個(gè)繼承而來的方法就叫做重寫該方法。

框架的類里定義的大部分方法都已被全面實(shí)現(xiàn);你可以直接調(diào)用它們,以獲得該類能夠提供的所有便利。對于這些方法,你不需要也不應(yīng)該嘗試重寫它們。其他的框架方法就可以被重寫了,但也并非時(shí)刻都有必要重寫。

但是,有些框架方法在使用之前要求先進(jìn)行重寫;它們存在的目的就是方便你向框架添加特定的行為。這些由框架實(shí)現(xiàn)的方法常常只做很少的事情或者什么有用的功能也沒有。為了給這些方法增添內(nèi)容,每個(gè)應(yīng)用都需要對它們進(jìn)行特性的實(shí)現(xiàn)?蚣軙(huì)在應(yīng)用運(yùn)行時(shí)生命期內(nèi)的合適時(shí)機(jī)調(diào)用這些方法。

調(diào)用還是重寫?

你在子類里重寫的框架方法通常不是由你親自調(diào)用的,至少不是由你直接調(diào)用。你只是重新實(shí)現(xiàn)該方法,并讓框架處理剩下的所有事情。實(shí)際上,基本上你重寫的特定版本的方法很少由你自己在代碼中進(jìn)行調(diào)用。通常來說,對于框架類聲明的公共方法,開發(fā)者們可以做下邊這兩件事:

  • 調(diào)用它們,讓類提供的功能發(fā)揮作用
  • 重寫它們,將你自己的代碼引入框架定義的程序模型中

有時(shí)某個(gè)方法會(huì)同時(shí)適用于這兩種情況;如果主動(dòng)調(diào)用,它會(huì)是一個(gè)非常有用的功能,同時(shí)也可以策略性地重寫它。但是在大部分情況下,如果你能夠調(diào)用某個(gè)方法,那么它就是由框架完全定義好的,無需在你的代碼中重復(fù)定義了。如果你必須在子類中重新實(shí)現(xiàn)某個(gè)方法,那么這個(gè)方法在框架中就是有著特定職責(zé)的,會(huì)在合適的時(shí)機(jī)由框架來調(diào)用。下圖描繪了這兩種框架方法。

\

在這張圖片里,假定你的自定義類里有個(gè)方法 myMethod,它調(diào)用了 setNeedsDisplay 方法,后者是由框架實(shí)現(xiàn)的?蚣苁紫葴(zhǔn)備好了繪制環(huán)境,然后調(diào)用框架聲明的 drawRect: 方法,這是已經(jīng)由自定義類重寫后的方法,能夠?qū)嶋H繪制圖形。

重寫方法并不是難事。只要在重新實(shí)現(xiàn)方法時(shí)格外小心,僅用一兩行代碼往往就能明顯改變父類定義的方法行為。

調(diào)用父類的實(shí)現(xiàn)

當(dāng)你重寫某個(gè)框架方法時(shí),你需要決定是否替換掉繼承到的方法行為,還是選擇擴(kuò)展或補(bǔ)充該行為。如果想要替換已有的行為,只需在方法的實(shí)現(xiàn)中輸入你自己的代碼;如果是想擴(kuò)展該行為,你需要調(diào)用父類的實(shí)現(xiàn)然后再提供自己的代碼。

如何調(diào)用父類的實(shí)現(xiàn)呢?只需向 super 發(fā)送一條同樣的消息調(diào)用該方法即可。向 super 發(fā)送消息時(shí),你就在調(diào)用的那個(gè)點(diǎn)上將父類的代碼“插入”了你重新實(shí)現(xiàn)的代碼。打個(gè)比方,假設(shè)有一個(gè)叫做 Celebrate 的類定義了一個(gè)方法performFireworks。當(dāng)框架在視圖中繪制并動(dòng)畫化一個(gè)煙火時(shí),你想在視圖中顯示一個(gè)橫幅。下邊的圖片顯示了此例中調(diào)用 super 的作用。

\

因此,決定調(diào)用 super 是基于你如何重新實(shí)現(xiàn)方法的:

  • 如果你想要補(bǔ)充父類實(shí)現(xiàn)中的行為,則要調(diào)用 super。
  • 如果你想要替換父類實(shí)現(xiàn)里的行為,那么就不要調(diào)用 super。

如果你是補(bǔ)充和擴(kuò)展父類的行為,還需要注意另外一件重要的事,那就是何時(shí)調(diào)用父類方法的實(shí)現(xiàn)。因?yàn),你可能需要在自己的代碼執(zhí)行之前讓父類的代碼產(chǎn)生作用,反之亦然。

關(guān)鍵詞:框架代碼ios

贊助商鏈接: