怎樣在Swift中使用CocoaPods

本文由yake_099(博客)翻譯自raywenderlich赠橙,作者:Joshua Greene

原文:How to Use CocoaPods with Swift

最近關于CocoaPods有很多的議論。你可能從別的開發(fā)者那里聽到過愤炸,或者在Github的目錄中看到過期揪。如果你之前從來沒有用過,你可能會問规个,"CocoaPods到底是什么凤薛?"

它不是神秘的亞馬遜區(qū)域的部落人用手撿出來的生可可的豆莢,肯定不是诞仓!讓CocoaPods website來回答可能是最好的:

CocoaPods是Cocoa項目的依賴管理工具缤苫。它有上千個能幫你優(yōu)雅地擴充自己項目的庫。

優(yōu)雅地擴展項目聽起來很令人好奇墅拭,但是什么是依賴管理工具呢榨馁?你為什么會需要它呢?

無論你正在創(chuàng)建一個什么樣的app帜矾,你都有可能會用到別的開發(fā)者的代碼翼虫,無論是以框架的形式還是庫的形式。你可能很熟悉UIKit和Foundation,這兩個都是蘋果提供的框架屡萤。

在這個教程中珍剑,你將會:

了解為什么要和第三方庫做朋友

安裝CocoaPods

在一個starter項目中使用CocoaPods

安裝使用并修改依賴關系文件來提高用戶體驗

了解語義化版本控制

為什么庫是你的朋友

盡管你并不一定非要使用第三方庫和框架,但是它們確實能節(jié)省你很多的時間死陆,可以讓你集中注意力在優(yōu)化自己的app上招拙,而不是敲無數(shù)行的你本不需要寫的代碼唧瘾。

你可以不通過依賴管理工具來使用第三方庫和框架,我們網(wǎng)站提供了關于這種使用方式的實踐性的教程别凤。例如饰序,這是我們的Alamofire教程SwiftyJSON教程

不使用依賴管理工具规哪,你可以簡單地通過手動方式將每個庫添加到你的工程里面求豫。然而,這個方法有幾個缺點:

更新一個庫到新的版本可能會很麻煩诉稍,尤其是一個庫依賴于另外一個庫的情況蝠嘉,那么就必須將這幾個庫全部更新。

在項目中添加三方庫可能會需要在代碼中做一些本地的修改杯巨,這使得之后更新版本更加困難蚤告。

判斷你的app中用到的庫的當前版本也是一件困難的事,尤其是當你沒有提前記錄下來的時候服爷。

如果沒有一個中央位置來查看所有可用庫的話杜恰,查找新庫也是一件很困難的事。

CocoaPods幫你克服以上問題甚至更多別的問題仍源。它抓取庫代碼箫章,解決庫之間的依賴性問題,幫你查找并發(fā)現(xiàn)新的庫镜会,甚至以最簡便的方式為你的項目配置正確的環(huán)境。

前提

這篇教程要求你熟悉基礎的iOS和Swift開發(fā)终抽。如果你完全不了解iOS或者Swift戳表,那么在看這篇教程之前,你最好看下我們網(wǎng)站上一些其他文章或者視頻教程昼伴,然后再回來看這篇匾旭。或者是深入來學習iOS Apprentice圃郊。

這篇教程也包含了使用了Core Graphics的一些類价涝。了解Core Graphics是一件有利的事,但不是必須的持舆。如果你想學習更多關于Core Graphics的知識色瘩,請閱讀我們的Modern Core Graphics With Swift系列。

這篇教程要求Xcode 6.3和Swift 1.2.

開始

首先你需要安裝CocoaPods逸寓。幸運的是居兆,CocoaPods被建立在Ruby上,而最近的Mac OS X版本帶有Ruby竹伸。這自從OS X 10.7之后就實現(xiàn)了泥栖。

打開終端并且輸入以下命令行:

1

sudo?gem?install?cocoapods

當要求的時候輸入你的密碼。終端的輸出結果看起來應該是這樣的:

你必須使用sudo來安裝CocoaPods,但是安裝后就無需再使用了吧享。

最后魏割,在終端輸入以下命令行來完成設置:

1

pod?setup?--verbose

這個過程可能需要幾分鐘的時間,因為它將CocoaPods Master Specs repository克隆到了你電腦上的~/.cocoapods/目錄下钢颂。

verbose選項記錄下了進程運行時的進展钞它,能讓你看到進程而不是一個僵在那里的屏幕。

太好了甸陌,現(xiàn)在你開始設置來使用CocoaPods了须揣。

代碼時間!

為客戶Ice Cream Shop, Inc.開發(fā)一款App

你的首要客戶是Ice Cream Shop, Inc钱豁。他們的冰淇淋太受歡迎了以至于不能在柜臺接收用戶訂單了耻卡。他們雇傭你來做一個漂亮的iOS應用,那樣就能讓用戶在他們的iPhone上下訂單了牲尺。

你開始開發(fā)app了卵酪,并且進展得還不錯。在這里下載開始程序谤碳。

打開IceCreamShop.xcodeproj溃卡,然后運行,你會看到一個非常好吃的香草冰淇淋蜒简。

用戶應該能從這個屏幕中選擇冰淇淋的口味瘸羡,但是還不太可能,因為你還沒有完成這個功能搓茬。

從Views/Storyboards&Nibs中打開Main.storyboard來看app的布局∮汤担現(xiàn)在我們來快速整體地看一下這個app的核心,"選擇你的口味"那一屏:

PickFlavorViewController處理用戶交互卷仑,例如峻村,用戶選擇了冰淇淋的一種口味。

PickFlavorDataSource是collection view所展示的不同冰淇淋口味的數(shù)據(jù)源锡凝。

IceCreamView是一個自定義的view粘昨,可以用來展示冰淇淋圓錐形的蛋卷,并且它以Flavormodel來支撐窜锯。

ScoopCell是一個自定義的collectionviewcell张肾,它包含了一個ScoopView,這個view也是以Flavormodel來支撐的锚扎。

由于每個冰淇淋店一般都會有一些招牌口味捌浩,每個也有他們本地的風味。因此工秩,F(xiàn)lavor的實例中包含的數(shù)據(jù)需要通過web service來提供尸饺。

然而进统,這還沒有回答問題,"為什么用戶不能選擇一個冰淇淋口味浪听?"

在Controllers這個分組下面螟碎,打開PickFlavorViewController.swift,你會看到一個備用的方法:

1

2private?func?loadFlavors()?{

//?Implement?this}

哈哈迹栓,這里面沒有口味掉分,你需要實現(xiàn)它。

你可以使用NSURLConnection或NSURLSession并用你自己寫的網(wǎng)絡類克伊,這兒還有一個更簡單的辦法:Alamofire酥郭,一個開源的網(wǎng)絡庫。

你可能想就這么把它下載下來并將文件拖拽到工程里面愿吹。然而不从,那是很麻煩的方法。CocoaPods提供了更加優(yōu)雅和靈活的解決方法犁跪。

所以椿息,閑話少說...

安裝你的第一個依賴管理工具

首先你要關掉Xcode

是的,你說的對坷衍,該創(chuàng)建Podfile了寝优,在那兒你要定義工程的依賴管理。

打開終端枫耳,用 cd 命令進入包含你IceCreamShop項目的那個目錄下:

1

cd?~/Path/To/Folder/Containing/IceCreamShop

接下來乏矾,輸入下面的命令:

1

pod?init

這將為你的項目創(chuàng)建一個PodFile

輸入下面的命令行打開PodFile,并使用Xcode進行編輯:

1

open?-a?Xcode?Podfile

注意:你不能使用TextEdit來編輯Podfile迁杨,因為它有可能用圖形化的更有吸引力的typeset quotes代替standard quotes钻心,這可能導致CocoaPods不能理解并拋出錯誤,所以最好用Xcode或者別的編程文本編輯器來編輯你的Podfile仑最。

默認的podFile看起來是這樣的:

1

2

3

4

5#?Uncomment?this?line?to?define?a?global?platform?for?your?project#?platform?:ios,?'6.0'

target'IceCreamShop'do

end

target'IceCreamShopTests'do

end

將注釋的內容替換成下面的兩行:

1

platform?:ios,"8.0"use_frameworks!

這就告訴了CocoaPods--你的項目使用的是iOS 8.0,并且將使用框架來代替靜態(tài)庫帆喇。

想要在Swift中使用CocoaPods警医,你必須明確的寫出use_frameworks! 來選擇使用框架。如果你忘了寫這個坯钦,CocoaPods能檢測到你使用使用Swift CocoaPods预皇,你安裝pods的時候就會報錯。

如果你僅僅使用過Swift編程,這可能看起來有些奇怪--那是因為Podfiel實際上使用Ruby寫的婉刀。你無需為了使用CocoaPods而學習Ruby吟温,但是你要知道即使是很小的文字錯誤通常也會使CocoaPods出錯。

關于“庫”

你會看到"library"通常代指庫或框架突颊。很抱歉這個教程也在無意間混雜了這兩個概念鲁豪。實際上潘悼,當某人提到"Swift library",他們實際上指的是"Swift dynamic frameworks",因為swift不允許靜態(tài)庫爬橡。

你可能想知道治唤,"庫(library)和框架(frameworkd)和cocoaPod之間的不同之處"。

Cocoapod或者簡寫為"pod"是一種慣常的叫法糙申,用來表示使用Cocoapods工具添加庫或者框架到你的應用程序中宾添。

iOS 8引入了動態(tài)框架,這就允許了代碼柜裸、圖片和其他的東西(assets)可以被一起打包缕陕。在iOS 8之前,CocoaPods被作為靜態(tài)庫來創(chuàng)建疙挺,就是很"臃腫的"二進制文件扛邑。這意味著它包含了一些代碼說明設置(例如i386 for the simulator, armv7 for devices等),但是它們不允許包含任何資源衔统,例如圖片或資產(chǎn)鹿榜。

另外一個重要的區(qū)別是動態(tài)框架有命名空間類,而靜態(tài)庫沒有锦爵。所以舱殿,如果單個項目中不同的靜態(tài)庫里分別有一個叫做MyTestClasses的類,那么Xcode可能不能成功創(chuàng)建工程因為它會因重復的標識而導致連接失敗险掀。然而沪袭,Xcode很樂意在一個工程里的不同框架下分別有一個名字相同的類。

為什么這很重要樟氢?不像OC冈绊,標準的Swift運行時庫(runtime libraries)沒有包含在iOS中!這意味著你的框架必須包含了必要的Swift運行時庫埠啃。因此死宣,用Swift語言寫的pods必須以動態(tài)框架形式創(chuàng)建。如果蘋果允許Swift靜態(tài)庫碴开,那么使用同一個標準運行時依賴的不同庫中將會產(chǎn)生重復符號毅该。

幸運的是,CocoaPods為你做了這些事潦牛。它甚至能做到一次性包含需要的依賴關系眶掌。你所要做的就是在使用swift cocoaPods時記得在Podfile中包含use_frameworks! ,那就沒問題了巴碗。

amazing朴爬,對不對肾筐?

安裝你的第一個依賴關系

這是使用cocoapods安裝你的依賴性文件的最后的時刻蒲障。將下面的內容添加到你的Podfile里面

1

pod'Alamofire','1.2.3'

這個是告訴CocoaPods你想添加1.1.4版本的Alamofire到你的工程中作為一個依賴性文件与殃,這是寫這篇教程時的最新版本该酗。

保存并關閉podFile

現(xiàn)在你需要告訴Cocoapods為你的工程安裝依賴性文件。在終端中輸入下面的命令蚣常,但是要首先確認你還在包含了IceCreamShop和Podfile的目錄下:

1

pod?install

你會看到輸出結果與下面的類似

1

2

3

4

5Analyzing?dependencies

Downloading?dependencies

Installing?Alamofire?(1.1.4)Generating?Pods?project

Integrating?client?project

[!]?Please?close?any?current?Xcode?sessions?and?use?`IceCreamShop.xcworkspace`forthisproject?from?now?on.

使用Finder打開你的工程文件夾市咽,你看看到CocoaPods創(chuàng)建了一個新的IceCreamShop.xcworkspace文件和一個Pods文件來存儲所有的工程依賴文件。

注意:從現(xiàn)在開始抵蚊,就像命令行警告提示的施绎,你必須使用workspace文件而不是project,否則你將遇到編譯錯誤贞绳。

太棒了谷醉!你已經(jīng)使用CocoaPods添加了你的第一個依賴管理。

使用安裝好的Pods

如果已經(jīng)打開了Xcode工程冈闭,那要關閉它并打開IceCream.xcworkspace.

打開PickFlavorViewController.swift俱尼,在現(xiàn)有的導入下添加以下代碼:

1

import?Alamofire

點擊command+b進行編譯。如果一切都沒有問題萎攒,你不會收到任何編譯錯誤的遇八。

接下來,用下面的代碼代替loadFlavors()方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16private?func?loadFlavors()?{

let?urlString?="http://www.raywenderlich.com/downloads/Flavors.plist"http://?1

Alamofire.request(.GET,?urlString,?encoding:?.PropertyList(.XMLFormat_v1_0,?0))

.responsePropertyList?{?request,?response,?array,?errorin//?2

iflet?error?=?error?{

println("Error:?\(error)")//?3

}elseiflet?array?=?array?as??[[String:?String]]?{//?4

ifarray.isEmpty?{

println("No?flavors?were?found!")//?5

}else{

self.flavors?=?self.flavorFactory.flavorsFromDictionaryArray(array)

self.collectionView.reloadData()

self.selectFirstFlavor()

}

}

}}

下面是對這個過程的詳細描述:

1.你用Alamofire創(chuàng)建了一個get請求耍休,并下載了一個包含冰淇淋口味的plist文件刃永。

2.一般你去看查看請求是否出錯并解析錯誤。現(xiàn)在如果出錯的話你只需要打印錯誤羊精。

3.將一個AnyObject?類型數(shù)組轉換為字典數(shù)組斯够。

4.如果數(shù)組是空的,你只需要打印一個錯誤信息喧锦。

5.如果一切都OK的話读规,你就將FlavorFactory方法創(chuàng)建的包含F(xiàn)lavor對象的數(shù)組賦值給self.flavors。這是一個同事為你寫的類燃少,是用來將裝了字典類型對象的數(shù)組轉換為Flavor對象束亏。如果你喜歡的話你可以仔細看看這個工廠類,但是它對教程的其他部分不是特別重要阵具。

編譯并運行碍遍!現(xiàn)在你可以選擇一個冰淇淋口味了!

選擇裝飾物

app看起來很不錯了怔昨,但是你仍然可以進行優(yōu)化雀久。

你有沒有注意到app花費了幾秒鐘的時間來下載flavors文件宿稀?如果你的網(wǎng)絡很快的話你可能注意不到趁舀,但是用戶不會都這么幸運的。

為了讓用戶理解app現(xiàn)在正在加載什么內容祝沸,你可以顯示一個加載指示器矮烹。MBProgressHUD是個很不錯的加載指示器.并且它支持CocoaPods越庇,多么的巧合!

你需要把這個加入到你的podfile里面奉狈。你現(xiàn)在不用通過命令行打開podfile了卤唉,你可以在工作區(qū)的pods中找到它。

打開podFile并在Alamofire后面加入下面幾行:

1

pod'MBProgressHUD','~>?0.9.0'

保存文件仁期,并在終端通過pod install命令來安裝依賴文件桑驱,就像你之前做的那樣。

這次發(fā)現(xiàn)什么不同的了嗎跛蛋?對熬的,你寫出了具體的版本號~>0.9.0。這兒會發(fā)生什么呢赊级?

Cocoapods建議所有的pods都使用語義化版本號(Semantic Versioning)押框。

語義化版本號

這三個數(shù)字被定義為主要的,次要的和補丁版本號理逊。例如橡伞,版本號0.9.0會被翻譯為

當主要的(major)版本號數(shù)字增加時, 意味著你做了一些不能兼容舊版本的更新晋被。當你將pod升級到下一個主要版本時兑徘,你可能需要修復編譯錯誤,否則pod可能跟之前表現(xiàn)得不太一樣墨微。

當次要(minor)版本號增加時道媚,意味著增加了新功能,但同時兼容舊版本翘县。當你決定升級時最域,你可能需要也可能不需要新的功能,但是它不應該引起編譯錯誤或者改變現(xiàn)有的功能锈麸。

當補抖浦(patch)版本號增加的時候,這意味著做了bug修復忘伞。但是沒有沒有增加也沒有改變功能薄翅。一般來說,你會希望盡快更新補丁版本到最新的版本氓奈,以便使用最新最穩(wěn)定版本的pod翘魄。

最后,最高版本號(major>minor>patch)必須按照以上規(guī)則逐步增加舀奶,而較低的版本號必須從0開始暑竟。

需要一個例子嗎?

考慮一個當前版本為1.2.3的pod育勺。

如果做了一些不能向后兼容的改變但荤,沒有新的功能罗岖,但是修改了現(xiàn)有的bug,那么下一個版本是2.0.0

挑戰(zhàn)時間

1.如果一個pod當前版本號是2.4.6腹躁,并且做了一些修復bug的改變桑包,添加了一些向后兼容的功能,新版本應該是多少呢纺非??

答案:2.5.0

解釋:如果修改包含向后兼容的新功能哑了,次要版本號(monir)就要增加了,并且補丁版本號(patch)就要被置為0.

2.如果一個pod的當前版本是3.5.8烧颖,并且對當前的功能做了一些改變垒手,新版本應該是多少?

答案:4.0.0

解釋:如果改變修改了現(xiàn)有的功能倒信,那么這就是不向后兼容的科贬。所以,主要版本號(major)必須增加鳖悠,而次要版本和補充版本置為0.

3.如果一個pod的向前版本號是10.20.30并且只修復了一些bug榜掌,那么新版本號應該是多少?

答案:10.20.31

解釋:如果只修復了bug乘综,補充版本號(patch)就要增加了憎账。

說了這么多,這兒有一個例外:

如果一個pod的版本低于1.0.0卡辰,這就被認為是測試版胞皱,次要版本號(minor)增加可能意味著向后兼容的改變。

所以在MBProgressHUB中使用~>0.9.0意味著你需要安裝大于或者等于0.9.0但是小于0.10.0的最新的版本.

這就保證了你在安裝pod的時候獲得了最新的bug修復九妈,但是不會意外的拉去向后兼容的改變反砌。這兒還有一些其他的可用操作。具體的列表萌朱,請看Podfile Syntax Reference宴树。

顯示進程

現(xiàn)在,回到PickFlavorViewController.swift晶疼,在其他的引用下面添加下面的內容

1

import?MBProgressHUD

下一步酒贬,在loadFlavors()后面加入以下方法

1

2

3

4

5private?func?showLoadingHUD()?{

let?hud?=?MBProgressHUD.showHUDAddedTo(contentView,?animated:true)

hud.labelText?="Loading..."}

private?func?hideLoadingHUD()?{

MBProgressHUD.hideAllHUDsForView(contentView,?animated:true)}

現(xiàn)在在loadFlavors()方法中,添加下面代碼:

1

2

3

4

5

6private?func?loadFlavors()?{

let?urlString?="http://www.raywenderlich.com/downloads/Flavors.plist"

showLoadingHUD()//?<--?Add?this?line

Alamofire.request(.GET,?urlString,?encoding:?.PropertyList(.XMLFormat_v1_0,?0))

.responsePropertyList?{?request,?response,?array,?errorinself.hideLoadingHUD()//?<--?And?this?line???????if?let?error?=?error?{

//...

就像方法名字所表明的翠霍,showLoadingHUD()方法會在GET請求下載時產(chǎn)生一個MBProgressHUD的實例對象锭吨,當請求結束時hideLoadingHUD()會將HUD隱藏。由于showLoadingHUD()在閉包之外所以它不需要前置代碼self寒匙。

編譯運行×闳纾現(xiàn)在你會看到一個加載指示器:

干的漂亮!用戶現(xiàn)在可以選擇他們最喜歡的冰淇淋口味了,并且在口味文件下載的時候會顯示一個正在加載的指示器埠况。

下一步

你可以從這兒下載完整的項目

恭喜你,現(xiàn)在你已經(jīng)學會了使用cocoapods的基礎棵癣,包括創(chuàng)建和修改依賴性文件辕翰,并且理解了語義化版本號。現(xiàn)在你可以準備開始在你自己的項目中使用他們了狈谊。

當然你 還可以用cocoapods做很多別的事喜命。你可以在Cocoapods官方網(wǎng)站上搜索現(xiàn)有的pods。也可以參考Cocoapods指南去學習如何使用這個杰出工具的更多細節(jié)內容河劝。但是要記住壁榕,一旦你開始使用你會好奇你曾經(jīng)是怎么不用它來進行管理的!

希望你享受閱讀這篇教程的過程我寫的時候赎瞎。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末牌里,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子务甥,更是在濱河造成了極大的恐慌牡辽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敞临,死亡現(xiàn)場離奇詭異态辛,居然都是意外死亡,警方通過查閱死者的電腦和手機挺尿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門奏黑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人编矾,你說我怎么就攤上這事熟史。” “怎么了窄俏?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵以故,是天一觀的道長。 經(jīng)常有香客問我裆操,道長怒详,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任踪区,我火速辦了婚禮昆烁,結果婚禮上,老公的妹妹穿的比我還像新娘缎岗。我一直安慰自己静尼,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鼠渺,像睡著了一般鸭巴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拦盹,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天鹃祖,我揣著相機與錄音,去河邊找鬼普舆。 笑死恬口,一個胖子當著我的面吹牛,可吹牛的內容都是我干的沼侣。 我是一名探鬼主播祖能,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛾洛!你這毒婦竟也來了养铸?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤轧膘,失蹤者是張志新(化名)和其女友劉穎揭厚,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扶供,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡筛圆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了椿浓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片太援。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖扳碍,靈堂內的尸體忽然破棺而出提岔,到底是詐尸還是另有隱情,我是刑警寧澤笋敞,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布碱蒙,位于F島的核電站,受9級特大地震影響夯巷,放射性物質發(fā)生泄漏赛惩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一趁餐、第九天 我趴在偏房一處隱蔽的房頂上張望喷兼。 院中可真熱鬧,春花似錦后雷、人聲如沸季惯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勉抓。三九已至贾漏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間藕筋,已是汗流浹背纵散。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留念逞,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓边翁,卻偏偏與公主長得像翎承,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子符匾,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容