Protocol Oriented Programming in Swift | Swift面向協(xié)議編程初探

最近有時(shí)間萧恕,挑了幾個(gè)今年WWDC中比較感興趣的Session視頻來(lái)學(xué)習(xí)姑子,今天就抽時(shí)間整理一下關(guān)于Swift 2.0中一個(gè)比較新的概念面向協(xié)議編程乎婿。

相關(guān)的Session視頻鏈接如下:

寫在前面

面向協(xié)議編程是什么?

你可能聽過(guò)類似的概念:面向?qū)ο缶幊?/strong>街佑、函數(shù)式編程谢翎、泛型編程,再加上蘋果今年新提出的面向協(xié)議編程舆乔,這些統(tǒng)統(tǒng)可以理解為是一種編程范式岳服。所謂編程范式,是隱藏在編程語(yǔ)言背后的思想希俩,代表著語(yǔ)言的作者想要用怎樣的方式去解決怎樣的問(wèn)題吊宋。不同的編程范式反應(yīng)在現(xiàn)實(shí)世界中,就是不同的編程語(yǔ)言適用于不同的領(lǐng)域和環(huán)境,比如在面向?qū)ο缶幊趟枷胫辛眩_發(fā)者用對(duì)象來(lái)描述萬(wàn)事萬(wàn)物并試圖用對(duì)象來(lái)解決所有可能的問(wèn)題拖吼。編程范式都有其各自的偏好和使用限制,所以越來(lái)越多的現(xiàn)代編程語(yǔ)言開始支持多范式这吻,使語(yǔ)言自身更強(qiáng)壯也更具適用性吊档。

更多編程范式和相關(guān)概念請(qǐng)參看:維基百科:編程范式

對(duì)Swift語(yǔ)言所采用的編程范式感興趣的朋友可以參看這篇文章:多范式編程語(yǔ)言-以 Swift 為例

面向協(xié)議編程長(zhǎng)什么樣子?

在詳細(xì)解釋面向協(xié)議編程之前唾糯,我們先簡(jiǎn)單地概括一下面向協(xié)議編程長(zhǎng)什么樣子怠硼?它與我們熟悉的面向?qū)ο缶幊逃惺裁床灰粯樱?/p>

簡(jiǎn)單來(lái)說(shuō),面向協(xié)議編程是在面向?qū)ο缶幊袒A(chǔ)上演變而來(lái)移怯,將程序設(shè)計(jì)過(guò)程中遇到的數(shù)據(jù)類型的抽认懔А(抽象)由使用基類進(jìn)行抽取改為使用協(xié)議(Java語(yǔ)言中的接口)進(jìn)行抽取。更簡(jiǎn)單點(diǎn)舉個(gè)栗子來(lái)說(shuō)舟误,一個(gè)貓類葡秒、一個(gè)狗類,我們很容易想到抽取一個(gè)描述動(dòng)物的基類嵌溢,也會(huì)有人想到抽取一個(gè)動(dòng)物通用的協(xié)議眯牧,那后者就可以被叫做面向協(xié)議編程了。什么赖草?就是這樣而已学少?蘋果官方那么正式的稱Swift是一門支持面向協(xié)議編程的語(yǔ)言,難道就是這么簡(jiǎn)單的內(nèi)容疚顷?當(dāng)然不會(huì)旱易,有過(guò)面向?qū)ο缶幊探?jīng)驗(yàn)的人都會(huì)清楚,協(xié)議的使用限制很多腿堤,并不能適用于大多數(shù)情況下數(shù)據(jù)類型的抽象。而在Swift語(yǔ)言中如暖,協(xié)議被賦予了更多的功能和更廣闊的使用空間笆檀,在Swift 2.0中,更為協(xié)議增加了擴(kuò)展功能盒至,使其能夠勝任絕大多數(shù)情況下數(shù)據(jù)類型的抽象酗洒,所以蘋果開始聲稱Swift是一門支持面向協(xié)議編程的語(yǔ)言。

面向協(xié)議編程對(duì)比面向?qū)ο缶幊痰暮锰幵谀睦锛纤欤克鼤?huì)對(duì)我們程序的設(shè)計(jì)造成哪些影響樱衷?我們會(huì)在下文中繼續(xù)分析。

寫在中間

離開面向?qū)ο笪覀兪チ耸裁矗?/h4>

首先酒唉,讓我們來(lái)看看面向?qū)ο缶幊虨槲覀儙?lái)的好處矩桂。絕大多數(shù)熟悉一種或幾種面向?qū)ο缶幊陶Z(yǔ)言的開發(fā)者都能隨口說(shuō)出幾條面向?qū)ο缶幊痰膬?yōu)點(diǎn),比如數(shù)據(jù)的封裝痪伦、數(shù)據(jù)訪問(wèn)的控制侄榴、數(shù)據(jù)類型的抽象雹锣、代碼的可讀性和可擴(kuò)展性等。這意味著離開了面向?qū)ο缶幊涛覀円簿褪チ巳绱硕嗟暮锰帯?/p>

哦癞蚕,天吶蕊爵!不要這樣好嘛?

回頭仔細(xì)想想桦山,這些好處只有面向?qū)ο缶幊滩庞新镌苌洌刻O果給了我們另一種答案:It's Type, not Classes,是抽象的類型帶給我們?nèi)绱硕嗟暮锰幒闼⒉皇敲嫦驅(qū)ο笾械?strong>類会放,類只是抽象類型的一種方式。比如在Swift語(yǔ)言中寇窑,使用結(jié)構(gòu)體和枚舉也同樣能夠?qū)崿F(xiàn)對(duì)類型的抽象鸦概、數(shù)據(jù)的封裝和訪問(wèn)控制等,這些好處又都回來(lái)了甩骏。

那么有沒(méi)有什么是類能帶給我們窗市,而結(jié)構(gòu)體和枚舉辦不到的呢?當(dāng)然有饮笛,不然我們真的可以離開面向?qū)ο罅俗刹臁C嫦驅(qū)ο缶幊踢€有兩個(gè)非常重要的特性我們還沒(méi)有提到:繼承和多態(tài)。繼承和多態(tài)為我們帶來(lái)了豐富多彩的世界福青,想想我們Cocoa Touch中的框架摄狱,這才是我們所熟悉的面向?qū)ο缶幊蹋刮覀兡軌蜉p易地解決所面對(duì)的問(wèn)題无午,并使我們的代碼具有高度的可定制和可重用性媒役。

我們的世界終于好像正常了。

擁有面向?qū)ο笪覀冇值玫搅耸裁矗?/h4>

那么宪迟,面向?qū)ο缶幊淘趲Ыo我們這么多好處的同時(shí)酣衷,是否還附帶了其他一些特性呢?比如說(shuō):要花費(fèi)的代價(jià)次泽。

我們先來(lái)看出現(xiàn)的第一個(gè)問(wèn)題穿仪,多數(shù)面向?qū)ο笳Z(yǔ)言中的對(duì)象都是使用引用類型,在對(duì)象傳遞過(guò)程中只是將引用復(fù)制一份并指向原有的對(duì)象意荤,這樣就會(huì)出現(xiàn)問(wèn)題啊片。比如下面代碼所示的例子:

class Book {
    var name: String
    var pages: Int
    init(name: String, pages: Int) {
        self.name = name
        self.pages = pages
    }
}
class Person {
    var name: String
    var book: Book
    init(name: String, book: Book) {
        self.name = name
        self.book = book
    }
}
let 圍城 = Book(name: "圍城", pages: 888)
let 小明 = Person(name: "小明", book: 圍城) // 小明有一本全新的《圍城》
let 小剛 = Person(name: "小剛", book: 圍城) // 小剛也有一本全新的《圍城》
小明.book.pages = 88 // 小明淘氣把書弄壞了,只剩88頁(yè)了
print(小剛.book.pages) // 輸出結(jié)果:88  WTF! Where is my new book?

故事的結(jié)尾是:小剛因?yàn)榕獕臅粙寢尨蛄藒 不對(duì)啊玖像,小明哪去了紫谷?我也不知道~

相信大多數(shù)面向?qū)ο缶幊陶Z(yǔ)言的開發(fā)者都明白這是引用傳遞的原因,通常我們的解決辦法也很簡(jiǎn)單,每次賦值的時(shí)候都先拷貝一份再進(jìn)行賦值。當(dāng)我們嘗試在上述代碼中加入copy方法時(shí),卻發(fā)現(xiàn)在Swift中對(duì)象默認(rèn)并沒(méi)有copy方法痪欲,這是因?yàn)镾wift更推薦使用值類型變量而不是引用類型的變量。如果真的需要調(diào)用copy方法羹膳,你可以將Book類繼承自NSObject,但這樣的做法真的一點(diǎn)都不優(yōu)雅根竿,也不夠Swiftpyer陵像。實(shí)際上我們的問(wèn)題也可以采用如下的解決辦法:

class Book {
    var name: String
    var pages: Int
    init(name: String, pages: Int) {
        self.name = name
        self.pages = pages
    }
}
class Person {
    var name: String
    var book: Book
    init(name: String, book: Book) {
        self.name = name
        self.book = Book(name: book.name, pages: book.pages)
    }
}
let 圍城 = Book(name: "圍城", pages: 888)
let 小明 = Person(name: "小明", book: 圍城) // 小明有一本全新的《圍城》
let 小剛 = Person(name: "小剛", book: 圍城) // 小剛也有一本全新的《圍城》
小明.book.pages = 88 // 小明淘氣把書弄壞了,只剩88頁(yè)了
print(小剛.book.pages) // 輸出結(jié)果:888

我們?cè)赑erson的構(gòu)造方法中寇壳,為book屬性新創(chuàng)建了一本書醒颖,從而保證小明和小剛各自擁有自己的書。這個(gè)解決辦法可能并不適用于所有引用類型傳遞的情況壳炎,那么在Swift中泞歉,最好的解決辦法是什么呢?其實(shí)答案很簡(jiǎn)單匿辩,使用值類型而非引用類型腰耙。Swift中許多常見的數(shù)據(jù)類型、字符串铲球、集合類型挺庞,以及結(jié)構(gòu)體和枚舉都是值類型而非引用類型,值類型的變量在賦值時(shí)會(huì)自動(dòng)進(jìn)行一次低消耗的值拷貝稼病,對(duì)比對(duì)象的copy要更加高效而且不存在線程安全問(wèn)題选侨。所以我們上面這個(gè)故事的最好結(jié)局是:將Book修改為結(jié)構(gòu)體類型。

struct Book {
    var name: String
    var pages: Int
    init(name: String, pages: Int) {
        self.name = name
        self.pages = pages
    }
}
struct Person {
    var name: String
    var book: Book
    init(name: String, book: Book) {
        self.name = name
        self.book = book
    }
}
let 圍城 = Book(name: "圍城", pages: 888)
var 小明 = Person(name: "小明", book: 圍城) // 小明有一本全新的《圍城》
let 小剛 = Person(name: "小剛", book: 圍城) // 小剛也有一本全新的《圍城》
小明.book.pages = 88 // 小明淘氣把書弄壞了然走,只剩88頁(yè)了
print(小剛.book.pages) // 輸出結(jié)果:888

小剛終于得救了~

想了解更多值類型的使用及其相關(guān)信息可以參看:Session 414: Building Better Apps with Value Types in Swift

我們剛剛使用一個(gè)例子解釋了面向?qū)ο缶幊讨惺褂靡妙愋涂赡艹霈F(xiàn)的問(wèn)題援制,接下來(lái)我們談?wù)摿硪粋€(gè)非常重要的話題:繼承的代價(jià)。這并不是一個(gè)新穎的話題芍瑞,自面向?qū)ο缶幊陶Q生之日起就飽受爭(zhēng)議隘谣,我們經(jīng)常要忍受著愈加繁雜和龐大的繼承體系來(lái)獲得代碼的可重用性,而且隨著繼承層次的增加啄巧,代碼的復(fù)雜性會(huì)加速增長(zhǎng),隨之而來(lái)的bug也會(huì)越來(lái)越難以發(fā)現(xiàn)掌栅。這時(shí)我們可能需要依靠設(shè)計(jì)模式來(lái)找回我們的思路秩仆,然而大多數(shù)設(shè)計(jì)模式只能幫助你理順你的代碼結(jié)構(gòu),卻在同時(shí)更加加深了你的代碼的復(fù)雜度猾封。

繼承帶給我們的另一個(gè)好處就是多態(tài)澄耍,多態(tài)極大地增強(qiáng)了我們代碼的可擴(kuò)展性。然而就像“能量守恒定律”一樣,多態(tài)也帶來(lái)了一定的負(fù)面影響齐莲,那就是類型信息的缺失痢站。形象一點(diǎn)講,就是我們常常會(huì)寫出這樣的代碼:subClassObject as! SubClass选酗,向下類型轉(zhuǎn)換阵难。

那么問(wèn)題來(lái)了:什么是更好的抽象類型?

蘋果官方對(duì)這個(gè)問(wèn)題的回答如下:

  • 更多地支持值類型芒填,同時(shí)也支持引用類型
  • 更多地支持靜態(tài)類型關(guān)聯(lián)(編譯期)呜叫,同時(shí)也支持動(dòng)態(tài)派發(fā)(運(yùn)行時(shí))
  • 結(jié)構(gòu)不龐大不復(fù)雜
  • 模型可擴(kuò)展
  • 不給模型強(qiáng)制添加數(shù)據(jù)
  • 不給模型增加初始化任務(wù)的負(fù)擔(dān)
  • 清楚哪些方法該實(shí)現(xiàn)哪些方法不需實(shí)現(xiàn)

其實(shí)答案就是Swift中的面向協(xié)議編程,蘋果只是在自賣自夸而已殿衰。

面向協(xié)議編程

接下來(lái)我們就正式進(jìn)入Swift的面向協(xié)議編程的世界朱庆。首先我們來(lái)對(duì)比如下兩段示例代碼,代碼的功能是定義一個(gè)更具擴(kuò)展性的二分查找法闷祥。

class Ordered {
    func precedes(other: Ordered) -> Bool { fatalError("implement me!") }
}
class Number: Ordered {
    var value: Double = 0
    override func precedes(other: Ordered) -> Bool {
        return self.value < (other as! Number).value
    }
}
func binarySearch(sortedKeys: [Ordered], forKey k: Ordered) -> Int {
    var lo = 0
    var hi = sortedKeys.count
    while hi > lo {
        let mid = lo + (hi - lo) / 2
        if sortedKeys[mid].precedes(k) { lo = mid + 1 }
        else { hi = mid }
    }
    return lo
}
protocol Ordered {
    func precedes(other: Self) -> Bool
}
struct Number: Ordered {
    var value: Double = 0
    func precedes(other: Number) -> Bool {
        return self.value < other.value
    }
}
func binarySearch<T: Ordered>(sortedKeys: [T], forKey k: T) -> Int {
    var lo = 0
    var hi = sortedKeys.count
    while hi > lo {
        let mid = lo + (hi - lo) / 2
        if sortedKeys[mid].precedes(k) { lo = mid + 1 }
        else { hi = mid }
    }
    return lo
}

應(yīng)該不難看出兩者之間的區(qū)別以及孰優(yōu)孰劣娱颊,簡(jiǎn)單解釋一下前者的缺點(diǎn),反過(guò)來(lái)也就是后者的優(yōu)點(diǎn)了凯砍。

  • OC語(yǔ)言中沒(méi)有抽象類這個(gè)概念箱硕,所有抽象類都是靠文檔注釋標(biāo)明,這很蛋疼~
  • 其他類型若想使用該二分查找法果覆,必須繼承自O(shè)rdered抽象類颅痊,在單繼承體系中,該類型將無(wú)法再繼承其他類型
  • 方法參數(shù)接收的數(shù)組中局待,類型要求不嚴(yán)格斑响,可以放入多種不同類型的Ordered子類對(duì)象
  • 基于前一點(diǎn)原因,為保證嚴(yán)謹(jǐn)性钳榨,必須在方法實(shí)現(xiàn)內(nèi)部增加類型判斷舰罚,這更加蛋疼~~

基于上面的例子,我們可以稍微感受到面向協(xié)議編程在擴(kuò)展性上的優(yōu)勢(shì)了薛耻,這里再提幾個(gè)注意點(diǎn)营罢。

  • Swift 2.0新特性之一,將Self用于約束泛型饼齿,功能類似于OC中的instancetype饲漾,示例:extension Ordered where Self: Comparable
  • Swift 2.0另一個(gè)重要的新特性,協(xié)議可擴(kuò)展缕溉,意味著你不僅可以擴(kuò)展一個(gè)類型使其遵守Ordered協(xié)議考传,還可以直接擴(kuò)展某個(gè)協(xié)議,詳見如下兩段代碼示例证鸥。
// 擴(kuò)展類型
extension Int: Ordered {
    func precedes(other: Int) -> Bool {
        return self < other
    }
}
extension String: Ordered {
    func precedes(other: String) -> Bool {
        return self < other
    }
}
let intIndex = binarySearch([2, 3, 5, 7], forKey: 5) // 輸出結(jié)果2
let stringIndex = binarySearch(["2", "3", "5", "7"], forKey: "5") // 輸出結(jié)果2
// 擴(kuò)展協(xié)議:方式一
//extension Comparable {
//    func precedes(other: Self) -> Bool {
//        return self < other
//    }
//}
// 擴(kuò)展協(xié)議:方式二(Swift 2.0的推薦方式)
extension Ordered where Self: Comparable {
    func precedes(other: Self) -> Bool {
        return self < other
    }
}
extension Int: Ordered {}
extension String: Ordered {}
let intIndex = binarySearch([2, 3, 5, 7], forKey: 5) // 輸出結(jié)果2
let stringIndex = binarySearch(["2", "3", "5", "7"], forKey: "5") // 輸出結(jié)果2

從上面的代碼我們可以看出僚楞,協(xié)議可擴(kuò)展所帶來(lái)的功能之一就是能夠?yàn)閰f(xié)議中的方法提供默認(rèn)實(shí)現(xiàn)勤晚。

更多協(xié)議可擴(kuò)展所帶來(lái)的功能可以參看RayWenderlich上的這篇文章:

關(guān)于面向協(xié)議編程的完整示例程序可以參看蘋果官方的示例代碼:

寫在最后

個(gè)人總結(jié)

面向?qū)ο缶幊毯兔嫦騾f(xié)議編程最明顯的區(qū)別在于程序設(shè)計(jì)過(guò)程中對(duì)數(shù)據(jù)類型的抽取(抽象)上泉褐,面向?qū)ο缶幊淌褂妙惡屠^承的手段赐写,數(shù)據(jù)類型是引用類型;而面向協(xié)議編程使用的是遵守協(xié)議的手段膜赃,數(shù)據(jù)類型是值類型(Swift中的結(jié)構(gòu)體或枚舉)挺邀。

面向協(xié)議編程是在面向?qū)ο缶幊袒A(chǔ)上發(fā)展而來(lái)的,而并不是完全背離面向?qū)ο缶幊痰乃枷搿?/p>

面向?qū)ο缶幊淌莻ゴ蟮木幊趟枷氩破剩彩钱?dāng)今主流的編程思想悠夯,它的問(wèn)題在于被過(guò)多的使用在其實(shí)并不需要使用它的情況下。

Swift是一門支持多編程范式的語(yǔ)言躺坟,既支持面向?qū)ο缶幊搪俨梗仓С置嫦騾f(xié)議編程,同時(shí)還支持函數(shù)式編程咪橙。在項(xiàng)目開發(fā)過(guò)程中夕膀,控制器和視圖部分由于使用系統(tǒng)框架,應(yīng)更多采用面向?qū)ο缶幊痰姆绞矫勒欤欢P突驑I(yè)務(wù)邏輯等自定義類型部分产舞,則應(yīng)優(yōu)先考慮面向協(xié)議編程。

PS. 這篇文章的寫作過(guò)程持續(xù)了很長(zhǎng)時(shí)間菠剩,中間幾乎夭折易猫,最后還是盡量將它寫完整(其實(shí)后半部分寫的很水)。面向協(xié)議編程是一個(gè)比較新的概念具壮,目前只是隱約可以看出它的一些長(zhǎng)處(在一些使用面向?qū)ο缶幊滩⒉惶m合的地方)准颓,不過(guò)蘋果已經(jīng)在自身框架中開始使用了,并確實(shí)改善了系統(tǒng)一些類型和方法的使用棺妓。

參考資料

最后攘已,讓我們記住這張圖:(Quiz: Who is Crusty at Apple?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市怜跑,隨后出現(xiàn)的幾起案子样勃,更是在濱河造成了極大的恐慌,老刑警劉巖性芬,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峡眶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡植锉,警方通過(guò)查閱死者的電腦和手機(jī)幌陕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)汽煮,“玉大人搏熄,你說(shuō)我怎么就攤上這事∠境啵” “怎么了心例?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鞋囊。 經(jīng)常有香客問(wèn)我止后,道長(zhǎng),這世上最難降的妖魔是什么溜腐? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任译株,我火速辦了婚禮,結(jié)果婚禮上挺益,老公的妹妹穿的比我還像新娘歉糜。我一直安慰自己,他們只是感情好望众,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布匪补。 她就那樣靜靜地躺著,像睡著了一般烂翰。 火紅的嫁衣襯著肌膚如雪夯缺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天甘耿,我揣著相機(jī)與錄音踊兜,去河邊找鬼。 笑死佳恬,一個(gè)胖子當(dāng)著我的面吹牛捏境,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播殿怜,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼典蝌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了头谜?” 一聲冷哼從身側(cè)響起骏掀,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柱告,沒(méi)想到半個(gè)月后截驮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡际度,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年葵袭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乖菱。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坡锡,死狀恐怖蓬网,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鹉勒,我是刑警寧澤帆锋,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站禽额,受9級(jí)特大地震影響锯厢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜脯倒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一实辑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藻丢,春花似錦剪撬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至问慎,卻和暖如春萍摊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背如叼。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工冰木, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人笼恰。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓踊沸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親社证。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逼龟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Swift的編程范式 編程范式是程序語(yǔ)言背后的思想。代表了程序語(yǔ)言的設(shè)計(jì)者認(rèn)為程序應(yīng)該如何被構(gòu)建和執(zhí)行追葡。常見的編程...
    Bobby0322閱讀 2,591評(píng)論 4 43
  • 第一章.面向?qū)ο笈c面向協(xié)議編程 本書是關(guān)于面向協(xié)議編程腺律。當(dāng)蘋果2015年的開發(fā)者大會(huì)上發(fā)布了Swift2,他們也宣...
    醬油不愛醋閱讀 1,391評(píng)論 0 7
  • 面向協(xié)議編程是什么宜肉? 你可能聽過(guò)類似的概念:面向?qū)ο缶幊淘染⒑瘮?shù)式編程、泛型編程谬返,再加上蘋果今年新提出的面向協(xié)議編程...
    Bobby0322閱讀 992評(píng)論 1 5
  • 第一章 面向?qū)ο缶幊毯兔嫦騾f(xié)議編程 這本書是關(guān)于面向協(xié)議編程的之斯。當(dāng)蘋果在 2015 年世界開發(fā)者大會(huì)上宣布 Swi...
    焉知非魚閱讀 4,995評(píng)論 19 25
  • 文章轉(zhuǎn)載:https://onevcat.com/2016/11/pop-cocoa-1/ (作者非常棒,建議大家...
    Buddha_like閱讀 438評(píng)論 0 0