泛型是面向對象裡另外一個重要的概念,除了多態,它進一步增加的代碼的重用範圍,而對於 Swift 語言來說,泛型貫穿了它的始終。
從 Print() 說起
我們從上課的第一天開始就在使用這個全局函數了,它讓我們得以在屏幕上顯示語句,用起來十分簡單,傳入一個字符串即可。
傳入字符串就顯示字符串,傳入整形就顯示數字……
等等!作為一個函數,它怎麼能接收兩種不同的參數!
好吧我們使用[……]
這節課我們一起來認識一下 Swift 中的錯誤處理
在調用方法和寫一個輪子的時候,總會有各種各樣奇奇怪怪的錯誤,就是已經正常編譯的軟件,也會出現一些不可預期的錯誤。不過,這些錯誤當中,有一些是可以被識別和捕捉的——它們可預期。
可預期的錯誤
為什麼我們說有一些錯誤是可以預料得到的呢?比如說讀取一個文件的時候文件不存在、保存一個文檔的時候目錄不可寫、下載文件的時候網絡無連接、傳送一個參數的[……]
不全都是動態
我們都知道,方法是放在實例裡運行的。也就是說方法執行的結果是依據實例屬性而來的,而實例的屬性是根據當前狀態而變化的——我們稱其為“動態”。
但真的全都是動態的嗎?其實不是,有些方法它會直接根據你的調用而給出結果,並不需要依據實例屬性的變化來產生變動——也就是說它是無論如何都會產生確定的結果的,我們稱這樣的方法為靜態方法,它是靜態的。
我們來舉個栗子看看:
[crayo[……]
前邊鋪墊了那麼多,現在終於要講到垃圾回收這個東西了。
弧
這不是方舟……這是自動引用計數(Automatic Reference Counting),這個東西是蘋果用來管理內存的。
它的功能就是那個垃圾堆上的垃圾回收器。它能夠保證所有在堆上運行的對像被釋放後不會一直駐留在堆上。保證了那塊內存會再分配給其他要使用的對像上。
何為釋放
說到對象會不會被垃圾回收器給收走,那就要看引用會[……]
在上一節課的末尾,我們最終明確了一個對象的創建過程,那麼,說起來創建一個對象的樣子很像是調用了一個方法,可這個方法到底是什麼呢?
初始化器
沒錯的,當我們初始化了一個類為對象的時候,我們確實調用了一個方法——初始化器。
初始化器其實就是一個特殊規定了的方法,它能夠為類進行初始化。
想像一下,如果沒有初始化器,那麼我們調用的類就一定是千篇一律的,每一次都要先創建對象,再修改它的屬性?[……]
是時候來看看對象和方法的生存空間了——想要了解面向對象,不知道方法和對象放在哪裡是一件很尷尬的事情——畢竟我們還是要面對垃圾收集器的,想要讓垃圾收集器幫你做更多的事情,我們就得一定程度上了解它的工作機制,了解方法和對象存放在哪裡,否則的話,你就又要寫出一個不堪一擊的程序來了!
我們在前邊的課程當中已經基本地提過堆的概念,沒錯,對象(實例)是放在堆上的——我將它形像地描述為“垃圾堆”。
被堆[……]
上節課我們提到了協議,但是只講了它的一種應用方式,這節課我們就來深入地了解一下這個用起來和 class 差不多的協議究竟有什麼高深奧義。
現在,我們要再一次回顧那個可恥的繼承樹:
這裡我們寫了武器……是用來進行攻擊和防守的。那麼,作為一個遊戲,武器的模型不能夠單單只用在這一個地方,不然的話開發的成本就太大了——我們要盡可能的榨乾代碼的價值。
我們與設計師溝通以後,設計師想[……]
說了方法的重寫,我們再回過頭來看看那個繼承樹:
這個看起來應該還行,我們可以創建大刀的實例,創建手槍的實例……
但是如果我要這樣寫呢?
| 1 | var 武器 = 武器() | 
那麼問題來了:挖掘機……
不,我們的問題是“武器”到底是個什麼東西?
我們說“動物”,人是動物,鳥是動物,狗、貓都是動物,那有沒有個動物是動物呢?
答案是沒[……]
說了那麼多次的重寫,這次我們就來認真的對待一下方法的重寫。
合約
我們說了,繼承就相當於是簽訂合約,我們繼承出來的子類一定要遵守這個合約,那麼就算你想要做一些合約裡沒有的事情,也要遵守合約的規範,所以,你重寫方法,也一定要符合方法的類型。
我們講過方法的類型,它以 ()->() 這樣來表示。所以,重寫的方法也一定要遵守這個類型即接收參數返回參數類型要相同……名字要相同還需要我說嗎?[……]
上一節課我們說完了繼承,那這節課我們就繼續深入,來看看繼承樹的大招是什麼。
可能我和你說起多態這個發音,你最先想到的應該是高中生物裡講的“多肽”;好吧,這兩者之間唯一相同的可能就是發音了。
繼承的意義
我們說繼承實現的意義非凡,它大大降低了我們代碼中的冗餘行數,降低了代碼的維護難度……
其實,我沒有提到繼承的另一個意義——合約。
上一節課我們做了演示,繼承代表了子類獲得了父類[……]
上節課我們具體地講述了繼承的機制,並且也設計了一個繼承樹,那麼問題來了:我不是要問挖掘機技術哪家強?我是要問如何來確定一個類是另一個類的子類呢?我們又如何設計一個類而不是某個類中的屬性呢?
“是一個”與“有一個”
這裡我們就要用這麼一個方法來檢驗它們二者之間的關係了:
我們說,手槍是槍械——OK,沒有問題,那麼手槍這個類就是槍械的子類。
還有長劍是一把劍,是一個冷兵器——沒問題,那這樣[……]
我們這次一起來回顧一下之前幾節課裡提到的繼承,我們曾在初見OPEN 裡用了一個開發手機(系統)的栗子來描述繼承這個東西,相信大家還有印象。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class CellPhone {     func call() {         print("Call someone!")     }     func powerUp () {         print("Welcome!")     }     func powerDown() {         print("Goodbye~")     }     func sendMessage() {         print("sent a Message!")     } } | 
繼承
那麼這節課我們就深入的來了解了解繼承這個概念。
這個其實也不難理解,你看,當你的父輩去世,那他們的財富就會由你繼承——好吧,這不是一件很值得開心的事情,但這畢竟是事實。[……]
這節課我們來試試開發一個簡單的命令行小遊戲,來完整的體驗一次所謂的“開發過程”。
遊戲設定是這樣的:
這是一種棋盤類游戲,我們來猜測敵人戰艦的位置,只要命中數發就可以擊沉它們。
我們給這些戰艦貼點標籤……比如各種網站吧?所以,這就成了一個攻擊網站的程序……捂臉。
遊戲目標
我們要玩家以最少的次數攻擊網站,把它擊垮。然後我們根據玩家的猜測次數來進行評分。
大致設計
我們畫一個7*7[……]
我們在上課之前,一起來回顧一下以前曾提過的“SoC”的概念,我們說這個叫做“Separation of Concerns”,我把它翻譯為責任分離——即不同的部分專注於自己的那一部分。或者說一個對象完成一個目標。
這樣做的目標既讓代碼更加模塊化易於維護,也讓系統運行效率更高。所以說,我們要讓對象之間的通信變得更加規範才行。
數據隱藏
你去看看你在寫代碼時候用到的那些框架,哪個給你直接展示了[……]
聲明一個變量
我們使用 var 來聲明一個變量,就好像從櫃子裡拿出了一個試管放在了實驗台上;
我們給變量規定了一個類型,就好像在試管上貼上了標籤;
那麼放入的試劑就必須是標籤上標記了的——否則可能導致中毒或者爆炸。
同樣的,如果我們試圖給一個儲存器放入一個錯誤的數據類型,那麼編譯器就會報錯——沒錯總有辦法能夠騙過編譯器——反正我不會教你這個方法,那樣就會導致程序崩潰啦。[……]
上一節課我們第一次領略了 OOP 的風采,於模棱兩可的類和對象究竟是什麼東西呢?這節課我們用一個簡單的小栗子來向你介紹。
嘗試解釋
我們說類和對象的關係是設計圖和產品的關係,就拿我們的房子來說,一棟樓肯定會有對應的設計圖,但設計圖絕不會只能對應一棟樓,至少一個小區肯定會用一套設計圖不是嗎?我們的“類”就是這個“設計圖”。我們用這個設計圖設計了對象的屬性、功能等等的一系列內容,然後通過實例化來產[……]
考慮到有的同學沒有 iPhone,但學習 Swift 語言大家至少都會有 OS X 操作系統,我們的代碼演示都會在 OS X 下完成,使用 CLI 界面。這樣雖然又顯得古老了,但相信我去掉 GUI 會讓你省心不少——因為那又是另一回事了。
那麼現在,讓我們來和 OOP 問個好
我們來看看,用 OOP 進行開發到底會是個什麼樣子?
考慮到我們現在並沒有很高的開發水平,那麼我們把所有的功能實[……]
我們都知道在 Java 中聲明一個抽象的類或者方法要使用 abstract 關鍵字,可是很遺憾熟悉的東西總會逝去,在 Swift 中已經沒有了這個標籤。
那麼,我們究竟要如何來聲明一個抽象的類呢?
私有構造器(初始化器)法
這一點倒是讓人很熟悉對吧?吧構造器私有了那這個類肯定就不能被初始化了,自然就不能創建對象實例……不過……哪有那麼多但是,反正能用就行了!
[crayon-6904e[……]