1继阻、《編寫(xiě)高質(zhì)量iOS與OSX代碼的52個(gè)有效方法》

再次整理耻涛,學(xué)習(xí)废酷;

一、熟悉Objective-C

第1條:熟悉Objective-C 語(yǔ)言的起源

1)Objective-C有Smaltalk演化而來(lái)抹缕,后者是消息型語(yǔ)言的鼻祖澈蟆;

1、消息機(jī)制和函數(shù)調(diào)用的關(guān)鍵區(qū)別:使用消息結(jié)構(gòu)的語(yǔ)言卓研,其運(yùn)行時(shí)所執(zhí)行的代碼由運(yùn)行環(huán)境倆決定趴俘;而函數(shù)調(diào)用的語(yǔ)言,由編譯器決定奏赘;

2寥闪、Objective-C是C的超集

3、Objective-C使用動(dòng)態(tài)綁定的消息結(jié)構(gòu)磨淌,在運(yùn)行時(shí)才會(huì)檢查對(duì)象類型疲憋;接收一條消息后,究竟應(yīng)執(zhí)行何種代碼伦糯,由運(yùn)行環(huán)境而非編譯器決定柜某;

第2條:在類的頭文件中盡量少引入其他頭文件

1、在編譯一個(gè)要使用的類的文件時(shí)敛纲,不需要知道這個(gè)類的全部細(xì)節(jié)喂击,只需要知道有這個(gè)類就行了;

前置聲明:@class類名(不過(guò)需要調(diào)用這個(gè)類的方法時(shí)淤翔,必須用#import引入頭文件)

***要點(diǎn):

1)除非確有必要翰绊,否則不要進(jìn)入頭文件。一般來(lái)說(shuō)旁壮,應(yīng)在某個(gè)類的頭文件中使用前置聲明來(lái)提及別的類监嗜,并在實(shí)現(xiàn)文件中引入哪些類的頭文件。這樣做可以盡量降低類之間的耦合抡谐;

2)有時(shí)無(wú)法使用前置聲明裁奇,比如要聲明某個(gè)類遵循一項(xiàng)協(xié)議。這種情況下麦撵,盡量把“該類遵循某協(xié)議”的這條聲明移至“class-continuation分類”中刽肠。如果不行的話,就把協(xié)議單獨(dú) 放在一個(gè)頭文件中免胃,然后將其引入音五;

第3條:多用字面量語(yǔ)法,少用與之等價(jià)的方法

1)NSString羔沙、NSNumber躺涝、NSArray、NSDictionary

NSString *str = @“my name is ruby”;

NSNumber *intNumber = @1;

NSArray *array = @[@1,@2,@3];

NSDictionary *dict = @{@“name”:@“ruby”,@“sex”:@“man”,@“age”:@24};

***要點(diǎn):

1扼雏、應(yīng)該使用字面量語(yǔ)法來(lái)創(chuàng)建字符串坚嗜、數(shù)值夯膀、數(shù)組、字典惶傻。更簡(jiǎn)潔棍郎;

2、應(yīng)該通過(guò)取下標(biāo)操作來(lái)訪問(wèn)數(shù)組下標(biāo)或字典中的鍵所對(duì)應(yīng)的元素银室;

3、用字面量語(yǔ)法創(chuàng)建數(shù)組或字典是励翼,若值中有nil蜈敢,則會(huì)拋出異常。因此汽抚,務(wù)必確保值不為nil抓狭;

第4條:多用類型常量,少用#define預(yù)處理指令

1)static const NSTimeInterval kAnimationDuration = 0.5;

常用命名方法:若常量局限于某“編譯單元”內(nèi)造烁,則在前面加k否过;若常量在類之外可見(jiàn),則通常以類名為前綴惭蟋;

2)聲明其他類可用的全局常量

// In the header file

extern NSString *const LoginViewStr;

// In the implementation file

NSString *const LoginViewStr = @“1234567”;

***要點(diǎn):

1苗桂、不要用預(yù)處理指令定義常量。這樣定義出來(lái)的常量不含類型信息告组,編譯器只是會(huì)在編譯前據(jù)此查找與替換操作煤伟。即使有人重新定義了常量值,編譯器也不會(huì)產(chǎn)生警告信息木缝,這將導(dǎo)致應(yīng)用程序中的常量不一致便锨;

2、在實(shí)現(xiàn)文件中使用static const 來(lái)定義“只在編譯單元內(nèi)可見(jiàn)的常量”我碟。由于此類常量不在全局符號(hào)表中放案,所以無(wú)須為其名稱加前綴;

3矫俺、在頭文件中使用extern來(lái)聲明全局變量吱殉,并在相應(yīng)實(shí)現(xiàn)文件中定義其值。這種常量要出現(xiàn)在全局符號(hào)表中恳守,所以其名稱應(yīng)加以區(qū)隔考婴,通常用與之相應(yīng)的類名做前綴;

第5條:用枚舉表示狀態(tài)催烘、選項(xiàng)沥阱、狀態(tài)碼

1)用枚舉來(lái)表示狀態(tài)機(jī)的狀態(tài)、傳遞給方法的選項(xiàng)以及狀態(tài)碼等值伊群;

2)如果把傳遞給某個(gè)方法的選項(xiàng)表示為枚舉類型考杉,而多個(gè)選項(xiàng)又可同時(shí)使用策精,那么久將各選項(xiàng)值定義為2的冪,以便通過(guò)按位或操作將其組合起來(lái)崇棠;

3)用NS_ENUM與NS_OPTIONS宏來(lái)定義枚舉類型咽袜,并指明其底層數(shù)據(jù)類型。這樣做可以確保枚舉是用開(kāi)發(fā)者所選的底層數(shù)據(jù)類型實(shí)現(xiàn)出來(lái)的枕稀,而不會(huì)采用編譯器所選的類型询刹;

4)在處理枚舉類型的switch語(yǔ)句中不要實(shí)現(xiàn)default分支。這樣的話萎坷,加入新枚舉之后凹联,編譯器就會(huì)提示開(kāi)發(fā)者:switch語(yǔ)句并未處理所有枚舉;

第2章 對(duì)象哆档、消息蔽挠、運(yùn)行期

當(dāng)應(yīng)用程序運(yùn)行起來(lái)以后,為其提供相關(guān)支持的代碼叫做“Object-C運(yùn)行期環(huán)境”(Objective-C runtime)瓜浸,它提供了一些使得對(duì)象之間能夠傳遞消息的重要函數(shù)澳淑,并且包含創(chuàng)建類實(shí)例所有的全部邏輯。

第6條:理解“屬性”這一概念

1)可以用@property語(yǔ)法來(lái)定義對(duì)象中所封裝的數(shù)據(jù)插佛;

2)通過(guò)“特質(zhì)”來(lái)指定存儲(chǔ)數(shù)據(jù)所需的正確語(yǔ)義杠巡;

3)在設(shè)置屬性所對(duì)應(yīng)的實(shí)例變量時(shí),一定要遵從該屬性所聲明的語(yǔ)義朗涩;

4)開(kāi)發(fā)iOS程序時(shí)應(yīng)該使用nonatomic屬性忽孽,因?yàn)閍tomic屬性會(huì)嚴(yán)重影響性能;

第7條:在對(duì)象內(nèi)部盡量直接訪問(wèn)實(shí)例變量

1)在對(duì)象內(nèi)部讀取數(shù)據(jù)時(shí)谢床,應(yīng)該直接通過(guò)實(shí)例變量來(lái)讀兄一,而寫(xiě)入數(shù)據(jù)時(shí),則應(yīng)通過(guò)屬性來(lái)寫(xiě)识腿;

2)在初始化方法及dealloc方法中出革,總是應(yīng)該直接通過(guò)實(shí)例變量來(lái)讀寫(xiě)數(shù)據(jù);

3)有時(shí)會(huì)使用惰性初始化技術(shù)配置某份數(shù)據(jù)渡讼,這種情況下骂束,必須通過(guò)“獲取方法”來(lái)訪問(wèn)屬性(_myname 通過(guò)下劃線取屬性值);

第8條:理解“對(duì)象等同性”這一概念

1)若想檢測(cè)對(duì)象的等同性成箫,請(qǐng)?zhí)峁癷sEqual:”與hash方法展箱;

2)相同的對(duì)象必須具有相同的哈希碼,但是兩個(gè)哈希碼相同的對(duì)象卻未必相同蹬昌;

3)不要盲目地逐個(gè)檢測(cè)每條屬性混驰,而是應(yīng)該依照具體需求來(lái)指定檢測(cè)方案;

4)編寫(xiě)hash方法時(shí),應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法栖榨;

第9條:以“類族模式”隱藏實(shí)現(xiàn)細(xì)節(jié)

1)類族模式可以把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡(jiǎn)單的公共接口后面昆汹;

2)系統(tǒng)框架中經(jīng)常使用類族

3)從類族的公共抽象基類中繼承子類時(shí)要當(dāng)心,若有開(kāi)發(fā)文檔婴栽,則應(yīng)首先閱讀满粗;

判斷某對(duì)象是否位于類族中:

if([classisKindOfClass:[SuperClassclass]]){

}

第10條:在即有類中使用關(guān)聯(lián)對(duì)象存放自定義數(shù)據(jù)

1)可以通過(guò)“關(guān)聯(lián)對(duì)象”機(jī)制來(lái)把兩個(gè)對(duì)象連起來(lái);

2)定義關(guān)聯(lián)對(duì)象時(shí)可指定內(nèi)存管理語(yǔ)義愚争,用以模仿定義屬性時(shí)所采用的“擁有關(guān)系”與“非擁有關(guān)系”映皆;

3)只有在其他做法不可行時(shí)才應(yīng)選用關(guān)聯(lián)對(duì)象,因?yàn)檫@種做法通常會(huì)引入難于查找的bug轰枝;

第11條:理解objc_msgSend的作用

1)消息由接受者劫扒、選擇子以及參數(shù)構(gòu)成。給某個(gè)對(duì)象“發(fā)送消息”也就相當(dāng)于在該對(duì)象上“調(diào)用方法”狸膏;

2)發(fā)給某對(duì)象的全部消息都要由“動(dòng)態(tài)消息派發(fā)系統(tǒng)(dynamic message dispatch system)來(lái)處理,該系統(tǒng)會(huì)查出對(duì)應(yīng)的方法添怔,并執(zhí)行其代碼”

OC代碼:

id returnValue = [someObject messageName:parameter];

轉(zhuǎn)換成C代碼:

方法void objc_msgSend(id self, SEL cmd,…..)

id returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);

該方法只描述了部分消息的調(diào)用過(guò)程湾戳,其他“邊界情況”則需要交由Object-C運(yùn)行環(huán)境中的另一些函數(shù)處理:

objc_msgSend_setet:如果待發(fā)送的消息要返回結(jié)構(gòu)體,

objc_msgSend_fpert:如果消息返回的是浮點(diǎn)數(shù)广料,

objc_msgSendSuper:如果要給超類發(fā)消息砾脑,

第12條:理解消息轉(zhuǎn)發(fā)機(jī)制

1)若對(duì)象無(wú)法響應(yīng)某個(gè)選擇子,則進(jìn)入消息轉(zhuǎn)發(fā)流程艾杏;

2)通過(guò)運(yùn)行期的動(dòng)態(tài)方法解析功能韧衣,我們可以在需要用到某個(gè)方法時(shí)再將其加入類中;

3)對(duì)象可以把其無(wú)法解讀的某些選擇子轉(zhuǎn)交給其它對(duì)象處理购桑;

4)經(jīng)過(guò)上述兩步之后畅铭,如果還是沒(méi)辦法處理選擇子,那就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制勃蜘;

將屬性聲明為@dynamic,這樣的話硕噩,編譯器就不會(huì)為其自動(dòng)生成實(shí)例變量及存取方法了;

@dynamic string,number,date;

第13條:用“方法調(diào)配技術(shù)”調(diào)式“黑盒方法”

1)在運(yùn)行期缭贡,可以向類中新增或替換選擇子所對(duì)應(yīng)的方法實(shí)現(xiàn)炉擅;

2)使用另一份實(shí)現(xiàn)來(lái)替換原有的方法實(shí)現(xiàn),這道工序叫“方法調(diào)配”阳惹,開(kāi)發(fā)者常用此技術(shù)向原有實(shí)現(xiàn)中添加新功能谍失;

3)一般來(lái)說(shuō),只有調(diào)式程序的時(shí)候才需要在運(yùn)行期修改方法實(shí)現(xiàn)莹汤,這種做法不宜濫用快鱼;

類的方法列表會(huì)把選擇子的名稱映射到相關(guān)的方法實(shí)現(xiàn)之上,使得“動(dòng)態(tài)消息派發(fā)系統(tǒng)”,能夠據(jù)此知找到應(yīng)該調(diào)用的方法攒巍。這些方法均以函數(shù)指針的形式來(lái)表示嗽仪,這種指針叫做IMP,

id (*IMP)(id柒莉,SEL闻坚,….)

Objective-C運(yùn)行期系統(tǒng)提供的幾個(gè)方法能夠用來(lái)操作選擇子映射表;

第14條:理解“類對(duì)象”的用意

1)每個(gè)實(shí)例都有一個(gè)指向Class對(duì)象的指針兢孝,用以表明其類型窿凤,而這些Class對(duì)象則構(gòu)成了類的繼承體系;

2)如果對(duì)象類型無(wú)法再編譯器確定跨蟹,那么就應(yīng)該使用類型信息查詢方法來(lái)探知雳殊;

3)盡量使用類型信息查詢方法來(lái)確定對(duì)象類型,而不要直接比較類對(duì)象窗轩,因?yàn)槟承?duì)象可能實(shí)現(xiàn)了消息轉(zhuǎn)發(fā)功能夯秃;

第3章接口與API設(shè)計(jì)

第15條:用前綴避免命名空間沖突

1)選擇與你的公司,應(yīng)用程序或二者皆有關(guān)聯(lián)之名稱作為類名的前綴痢艺,并在所有代碼中均使用這一前綴仓洼;

2)若自己所開(kāi)發(fā)的程序庫(kù)中用到了第三方庫(kù),則應(yīng)為其中的名稱加上前綴堤舒;

******蘋(píng)果保留了兩個(gè)字母作為前綴的權(quán)利(最好用三個(gè)以上的字母作為前綴)色建;

第16條:提供“全能初始化方法”

1)在類中提供一個(gè)全能初始化方法,并于文檔里指明舌缤。其它初始化方法均應(yīng)調(diào)用此方法箕戳;

2)若全能初始化方法與超類不同,則需覆寫(xiě)超類中的對(duì)應(yīng)方法国撵;

3)如果超類的初始化方法不適用于子類陵吸,那么應(yīng)該覆寫(xiě)這個(gè)超類的方法,并在其中拋出異常卸留;

第17條:實(shí)現(xiàn)description方法

1)實(shí)現(xiàn)description方法返回一個(gè)有意義的字符串走越,用以描述該實(shí)例;

2)若想在調(diào)式時(shí)打印出更詳細(xì)的對(duì)象描述信息耻瑟,則應(yīng)實(shí)現(xiàn)debugDescription方法旨指;用po 打印內(nèi)容,是調(diào)用description方法;

第18條:盡量使用不可變對(duì)象

1)盡量創(chuàng)建不可變的對(duì)象喳整;

2)若某屬性僅可于對(duì)象內(nèi)部修改谆构,則在“class-continuation分類”中將其由readonly屬性擴(kuò)展為readwrite屬性;

3)不要把可變的collection作為屬性公開(kāi)框都,則應(yīng)提供相關(guān)方法搬素,以此修改對(duì)象中的可變collection;

第19條:使用清晰而協(xié)調(diào)的命名方式

1)起名時(shí)應(yīng)遵從標(biāo)準(zhǔn)的Objective-C命名規(guī)范,這樣創(chuàng)建出來(lái)的接口更容易為開(kāi)發(fā)者所理解熬尺;

2)方法名要言簡(jiǎn)意賅摸屠,從左至右讀起來(lái)要像個(gè)日常用語(yǔ)中的句子才好;

3)方法名里不要使用縮略后的類型名稱粱哼;

4)給方法起名時(shí)的第一要?jiǎng)?wù)就是確保其風(fēng)格與你自己的代碼或所要集成的框架相符季二;

第20條:為私有方法名加前綴

1)給私有方法的名稱加上前綴,這樣可以很容易地將其同公共方法分開(kāi)揭措;

2)不要單用一個(gè)下劃線做私有方法的前綴胯舷,因?yàn)檫@樣做法是預(yù)留給蘋(píng)果公司用的;

第21條:理解Objective-C錯(cuò)誤模型

1)只有發(fā)生了可使整個(gè)應(yīng)用程序崩潰的嚴(yán)重錯(cuò)誤時(shí)绊含,才應(yīng)使用異常桑嘶;

2)在錯(cuò)誤不那么嚴(yán)重的情況下,可以指派“委托方法”來(lái)處理錯(cuò)誤躬充,也可以把錯(cuò)誤信息方法NSError對(duì)象里逃顶,經(jīng)由“輸出參數(shù)”返回給調(diào)用者;

第22條:理解NSCopying協(xié)議

1)若想令自己所寫(xiě)的對(duì)象具有拷貝功能充甚,則需要事項(xiàng)NSCopying協(xié)議口蝠;

2)如果自定義的對(duì)象分為可變版本與不可變版本,那么就要同時(shí)實(shí)現(xiàn)NSCopying與NSMutableCopying協(xié)議津坑;

3)復(fù)制對(duì)象是需決定采用淺拷貝還是深拷貝,一般情況下應(yīng)該盡量執(zhí)行淺拷貝傲霸;

4)如果你所寫(xiě)的對(duì)象需要深拷貝疆瑰,那么可考慮新增一個(gè)專門(mén)執(zhí)行深拷貝的方法;

第4章協(xié)議與分類

第23條:通過(guò)委托與數(shù)據(jù)源協(xié)議進(jìn)行對(duì)象間通信

1)委托模式為對(duì)象提供了一套接口昙啄,使其可由此將相關(guān)事件告知其他對(duì)象穆役;

2)將委托對(duì)象應(yīng)該支持的接口定義成協(xié)議,在協(xié)議中把可能需要處理的事件定義成方法梳凛;

3)當(dāng)某對(duì)象需要從另外一個(gè)對(duì)象中獲取數(shù)據(jù)時(shí)耿币,可以使用委托模式。這種情境下韧拒,該模式稱“數(shù)據(jù)源協(xié)議(data source protocal)”淹接;

4)若有必要,可實(shí)現(xiàn)含有位段的結(jié)構(gòu)體叛溢,將委托對(duì)象是否能響應(yīng)相關(guān)協(xié)議方法這一信息緩存至其中塑悼;

第24條:將類的實(shí)現(xiàn)代碼分散到便于管理的數(shù)個(gè)分類之中

1)使用分類機(jī)制把類的實(shí)現(xiàn)代碼劃分成易于管理的小塊;

2)將應(yīng)該視為“私有”的方法歸入名叫Private的分類中楷掉,以隱藏實(shí)現(xiàn)細(xì)節(jié)厢蒜;

第25條:總是為第三方類的分類名稱加前綴

1)向第三方類中添加分類時(shí),總應(yīng)給其名稱加上你專用的前綴;

2)向第三方類中添加分類時(shí)斑鸦,總應(yīng)給其中的方法名加上你專用的前綴愕贡;

第26條:勿在分類中聲明屬性

1)把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里;

2)在“class-continuation分類”之外的其他分類中巷屿,可以定義存取方法固以,但盡量不要定義屬性;

第27條:使用“class-continuation分類”隱藏實(shí)現(xiàn)細(xì)節(jié)

1)通過(guò)“class-continuation分類”向類中新增實(shí)例變量攒庵;

2)如果某屬性在主接口中聲明為“只讀”嘴纺,而類的內(nèi)部又要用設(shè)置方法修改此屬性,那么就在“class-continuation分類”中將其擴(kuò)展為“可讀寫(xiě)”浓冒;

3)把私有方法的原型聲明在“class-continuation分類”里面栽渴;

4)若想使類所遵循的協(xié)議不為人所知,則可于“class-continuation分類”中聲明稳懒;

第28條:通過(guò)協(xié)議提供匿名對(duì)象

1)協(xié)議可在某種程度上提供匿名類型闲擦。具體的對(duì)象類型可以淡化成遵從某協(xié)議的id類型,協(xié)議里規(guī)定了對(duì)象所應(yīng)實(shí)現(xiàn)的方法场梆;

2)使用匿名對(duì)象來(lái)隱藏類型名稱(或類名)墅冷;

3)如果具體類型不重要,重要的是對(duì)象能夠響應(yīng)(定義在協(xié)議里的)特定方法或油,那么可使用匿名對(duì)象來(lái)表示寞忿;

第5章內(nèi)存管理

第29條:理解引用計(jì)數(shù)

1)引用計(jì)數(shù)機(jī)制通過(guò)可以遞增遞減的計(jì)數(shù)器來(lái)管理內(nèi)存。對(duì)象創(chuàng)建好之后顶岸,其保留計(jì)數(shù)至少為1.若保留計(jì)數(shù)為正腔彰,則對(duì)對(duì)象繼續(xù)存留。當(dāng)保留計(jì)數(shù)降為0時(shí)辖佣,對(duì)象就被銷毀了霹抛;

2)在對(duì)象生命期中,其余對(duì)象通過(guò)引用來(lái)保留或釋放此對(duì)象卷谈。保留與釋放操作分別會(huì)遞增及遞減保留計(jì)數(shù)杯拐;

第30條:以ARC簡(jiǎn)化引用計(jì)數(shù)

1)ARC只負(fù)責(zé)管理Objective-C對(duì)象的內(nèi)存。尤其要注意:CoreFoundation對(duì)象不歸ARC管理世蔗,開(kāi)發(fā)者必須適時(shí)調(diào)用CFRetain/CFRelease端逼;

-(void)dealloc{

CFRelease(_coreFoundationObject);

}

第31條:在dealloc方法中釋放引用并解除監(jiān)聽(tīng)

1)在dealloc方法里,應(yīng)該做的事情就是釋放指向其它對(duì)象的引用污淋,并取消原來(lái)訂閱的“鍵值觀測(cè)”(KVO)或NSNotificationCenter等通知裳食,不要做其它事情;

2)如果對(duì)象持有文件描述等系統(tǒng)資源芙沥,那么應(yīng)該專門(mén)編寫(xiě)一個(gè)方法來(lái)釋放此種資源诲祸。這樣的類要和其使用中約定:用完資源后必須調(diào)用close方法浊吏;

3)執(zhí)行異步任務(wù)的方法不應(yīng)在dealloc里調(diào)用;只能在正常狀態(tài)下執(zhí)行的那些方法在不應(yīng)在dealloc里調(diào)用救氯,因?yàn)榇藭r(shí)對(duì)象已處在回收的狀態(tài)了找田;

第32條:編寫(xiě)“異常安全代碼”時(shí)留意內(nèi)存管理問(wèn)題

1)捕獲異常時(shí),一定要注意將try快內(nèi)所創(chuàng)立的對(duì)象清理干凈着憨;

2)在默認(rèn)情況下墩衙,ARC不生成安全處理異常所需的清理代碼。開(kāi)啟編譯器標(biāo)志后甲抖,可生成這種代碼漆改,不過(guò)會(huì)導(dǎo)致應(yīng)用程序變大,而且會(huì)降低運(yùn)行效率准谚;

ARC環(huán)境下基本不會(huì)使用異常安全代碼挫剑,極大影響效率,OC代碼中柱衔,只有當(dāng)應(yīng)用程序必須因異常狀態(tài)而終止才應(yīng)拋出異常(拋出異常沒(méi)有意義)樊破;

開(kāi)啟-fobjc-arc-exceptions,ARC也能生成處理異常所用的附加代碼唆铐;

第33條:以弱引用避免保留環(huán)

1)將某些引用設(shè)為weak哲戚,可避免出現(xiàn)“保留環(huán)”;

2)weak引用可以自動(dòng)清空艾岂,也可以不自動(dòng)清空顺少。自動(dòng)清空(autonilling)是隨著ARC而引入的新特性,由運(yùn)行期系統(tǒng)來(lái)實(shí)現(xiàn)王浴。在具備自動(dòng)清空功能的弱引用上祈纯,可以隨意讀取其數(shù)據(jù),因?yàn)檫@種引用不會(huì)指向已經(jīng)回收過(guò)的對(duì)象叼耙;

第34條:以“自動(dòng)釋放池”降低內(nèi)存峰值

1)自動(dòng)釋放池排布在棧中岩臣,對(duì)象收到autorelease消息后这吻,系統(tǒng)將其放入最頂端的池里;

2)合理運(yùn)用自動(dòng)釋放池剔猿,可降低應(yīng)用程序的內(nèi)存峰值癞松;

3)@autoreleasepool這種新式寫(xiě)法能創(chuàng)建出更為輕便的自動(dòng)釋放池爽撒;

第35條:用“僵尸對(duì)象”調(diào)用內(nèi)存管理問(wèn)題(***有點(diǎn)蒙)

1)系統(tǒng)在回收對(duì)象時(shí),可以不將其真的收回响蓉,而是把它轉(zhuǎn)化為僵尸對(duì)象硕勿。通過(guò)環(huán)境變量NSZombieEnabled可開(kāi)啟此功能;

2)系統(tǒng)會(huì)修改對(duì)象的isa指針枫甲,令其指向特殊的僵尸類源武,從而使改對(duì)象變?yōu)榻┦瑢?duì)象扼褪。僵尸類能夠響應(yīng)所有的選擇子,響應(yīng)方式為:打印一條包含消息內(nèi)容及其接受者的消息粱栖,然后終止應(yīng)用程序话浇;

第36條:不要使用retainCount

1)對(duì)象的保留計(jì)數(shù)看似有用,實(shí)則不然闹究,因?yàn)槿魏谓o定時(shí)間點(diǎn)上的“絕對(duì)保留計(jì)數(shù)”(absolute retain count)都無(wú)法反映對(duì)象生命的全貌幔崖;

2)引入ARC之后,retainCount方法就正式廢止了渣淤,在ARC下調(diào)用該方法會(huì)導(dǎo)致編譯器報(bào)錯(cuò)赏寇;

第6章:塊與大中樞派發(fā)

第37條:理解“塊”這一概念

1)塊是C、C++价认、Objective-C中的語(yǔ)法閉包嗅定;

2)塊可接受參數(shù)、也可返回值刻伊;

3)塊可以分配在椔督洌或堆上,也可以是全局的捶箱。分配在棧上的塊可拷貝到堆里智什,這樣的話,就和標(biāo)準(zhǔn)的Objective-C對(duì)象一樣丁屎,具備引用計(jì)數(shù)了荠锭;

self也是個(gè)對(duì)象,因而塊在捕獲它時(shí)也會(huì)將其保留晨川。如果self所指代的按個(gè)對(duì)象同時(shí)也保留了塊证九,那么這種情況通常會(huì)導(dǎo)致“保留環(huán)”;

理解全局塊共虑、棧塊愧怜、堆塊;

全局塊:

void (^block)() = ^{

NSLog(@“this is a block”);

}

第38條:為常用的塊類型創(chuàng)建typedef

1)以typedef重新定義塊類型妈拌,可令塊變量用起來(lái)更加簡(jiǎn)單拥坛;

2)定義新類型時(shí)應(yīng)遵從現(xiàn)有的命名習(xí)慣,勿使用名稱與別的類型相沖突尘分;

3)不妨為同一個(gè)塊簽名定義多個(gè)類型別名猜惋。如果要重構(gòu)的代碼使用了塊類型的某個(gè)別名,那么直需要修改相應(yīng)typedef中的塊簽名即可培愁,無(wú)須改動(dòng)其它typedef著摔;

用typedef重命名:

typedef int (^EOCSomeBlock)(BOOL flag,int value);

回調(diào):

-(void)startWithCompletionHandler:(void(^)(NSData *data,NSError *error))completion;

第39條:用handler塊降低代碼分散程度

1)在創(chuàng)建對(duì)象時(shí),可以使用內(nèi)聯(lián)的handler塊將相關(guān)業(yè)務(wù)邏輯一并聲明定续;

2)在有多個(gè)實(shí)例需要監(jiān)控時(shí)谍咆,如果采用委托模式禾锤,那么經(jīng)常需要根據(jù)傳入的對(duì)象來(lái)切換,而若用handler塊來(lái)實(shí)現(xiàn)卧波,則可直接將快與相關(guān)對(duì)象放在一起时肿;

3)設(shè)計(jì)API時(shí)如果用到了handler塊,那么可以增加一個(gè)參數(shù)港粱,使調(diào)用者可通過(guò)此參數(shù)來(lái)決定應(yīng)該把塊安排在哪個(gè)隊(duì)列上執(zhí)行螃成;

第40條:用塊引用其所屬對(duì)象時(shí)不要出現(xiàn)保留環(huán)

1)如果塊所捕獲的對(duì)象直接或間接地保留了塊本身,那么就得當(dāng)心保留環(huán)問(wèn)題查坪;

2)一定要找個(gè)適當(dāng)?shù)臅r(shí)機(jī)解除保留環(huán)寸宏,而不能把責(zé)任推給API的調(diào)用者;

如果在block代碼塊里面改變實(shí)例變量偿曙,必須獲取self氮凝,這樣就會(huì)導(dǎo)致“保留環(huán)”;用__weak修飾望忆;

第41條:多用派發(fā)隊(duì)列罩阵,少用同步鎖

1)派發(fā)隊(duì)列可用來(lái)表述同步語(yǔ)義(synchronizetion semantic),這種做法要比使用@synchronized塊或NSLock對(duì)象更簡(jiǎn)單启摄;

2)將同步與異步派發(fā)結(jié)合起來(lái)稿壁,可以實(shí)現(xiàn)與普通加鎖機(jī)制一樣的同步行為,而這么做卻不會(huì)阻塞執(zhí)行異步派發(fā)的線程歉备;

3)使用同步隊(duì)列及柵欄塊傅是,可以令同步行為更加高效;

理論上:運(yùn)用線程鎖可以保證線程安全蕾羊,但是無(wú)法保證線程的絕對(duì)安全(單個(gè)線程中多次訪問(wèn)某個(gè)屬性值時(shí)喧笔,其它線程可能會(huì)寫(xiě)入新值);

第42條:多用GCD龟再,要用performSelector系列方法

1)performSelector系列方法在內(nèi)存管理方面容易有疏失书闸。它無(wú)法確定要執(zhí)行的選擇子具體是什么,因而ARC編譯器也就無(wú)法插入適當(dāng)?shù)膬?nèi)存管理方法利凑;

2)performSelector系列方法所能處理的選擇子太過(guò)局限了浆劲,選擇子的返回值類型及發(fā)送給方法的參數(shù)個(gè)數(shù)都收到限制;

3)如果想把任務(wù)放在另一個(gè)線程上執(zhí)行截碴,那么最好不要用performSelector系列方法,而是應(yīng)該把任務(wù)封裝到塊里蛉威,然后調(diào)用大中樞派發(fā)機(jī)制的相關(guān)方法來(lái)實(shí)現(xiàn)日丹;

第43條:掌握GCD及操作隊(duì)列的使用時(shí)機(jī)

1)在解決多線程與任務(wù)管理問(wèn)題時(shí),派發(fā)隊(duì)列并非唯一方案蚯嫌;

2)操作隊(duì)列提供了一套高層的Objective-C API哲虾,能實(shí)現(xiàn)純GCD所具備的絕大部分功能丙躏,而且還能完成一些更為復(fù)雜的操作,哪些操作若改用GCD來(lái)實(shí)現(xiàn)束凑,則需另外編寫(xiě)代碼晒旅;

第44條:通過(guò)Dispatch Group機(jī)制,根據(jù)系統(tǒng)資源狀況來(lái)執(zhí)行任務(wù)

1)一系列任務(wù)可歸入一個(gè)dispatch group之中汪诉。開(kāi)發(fā)者可以在這組任務(wù)執(zhí)行完畢時(shí)獲得通知废恋;

2)通過(guò)dispatch group,可以在并發(fā)式隊(duì)列里同時(shí)執(zhí)行多項(xiàng)任務(wù)扒寄。此時(shí)GCD會(huì)根據(jù)系統(tǒng)資源狀況來(lái)調(diào)度這些并發(fā)執(zhí)行的任務(wù)鱼鼓。開(kāi)發(fā)者若自己來(lái)實(shí)現(xiàn)此功能,則需編寫(xiě)大量代碼

第45條:使用dispatch_once 來(lái)執(zhí)行只需運(yùn)行一次的線程安全代碼

1)dispatch_get_current_queue 函數(shù)的行為常常與開(kāi)發(fā)者所預(yù)期的不同该编。此函數(shù)已經(jīng)廢棄迄本,只應(yīng)做調(diào)試只用;

2)由于派發(fā)隊(duì)列是按層級(jí)來(lái)組織的课竣,所以無(wú)法單用某個(gè)隊(duì)列對(duì)象來(lái)描述“當(dāng)前隊(duì)列”這一概念嘉赎;

3)dispatch_get_current_queue函數(shù)用于解決由不可重入的代碼所引發(fā)的死鎖,然而能用此函數(shù)解決的問(wèn)題于樟,通常也能改用“隊(duì)列特定數(shù)據(jù)”來(lái)解決公条;

第46條:不要使用dispatch_get_current_queue

1)dispatch_get_current_queue函數(shù)的行為常常與開(kāi)發(fā)者所預(yù)期的不同。此函數(shù)已經(jīng)廢棄隔披,只應(yīng)做調(diào)試之用赃份;

2)由于派發(fā)隊(duì)列是按層級(jí)來(lái)組織的,所以無(wú)法單用某個(gè)隊(duì)列對(duì)象來(lái)描述“當(dāng)前隊(duì)列”這一概念奢米;

3)dispatch_get_current_queue函數(shù)由于解決由不可重入的代碼所引發(fā)的死鎖抓韩,然而能用此函數(shù)解決的問(wèn)題,通常也能改用“隊(duì)列特定數(shù)據(jù)”來(lái)解決鬓长;

- (void)viewDidLoad {

[superviewDidLoad];

//1谒拴、創(chuàng)建NSInvocationOperation對(duì)象

NSInvocationOperation*operation = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationDaYin)object:nil];

//[operation start];

//2、創(chuàng)建NSBlockOperation對(duì)象

NSBlockOperation*operation1 = [NSBlockOperationblockOperationWithBlock:^{

NSLog(@"operation1打印內(nèi)容:111111111111");

}];

//該方式創(chuàng)建可以添加額外任務(wù)涉波,任務(wù)執(zhí)行沒(méi)有先后順序英上;

[operation1addExecutionBlock:^{

NSLog(@"operation1添加的額外任務(wù):1111111*****");

//4、子線程給主線程傳值的兩種方法:該方法會(huì)在主線程執(zhí)行完之后再調(diào)用啤覆;優(yōu)先選擇第二種方法

//[self performSelectorOnMainThread:@selector(log:) withObject:@"1111111111" waitUntilDone:NO];

dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@"從子線程回到主線程打印的內(nèi)容:*******************");

});

}];

//[operation1 start];

NSBlockOperation*operation2 = [NSBlockOperationblockOperationWithBlock:^{

NSLog(@"operation2打印內(nèi)容:222222222");

}];

//[operation2 start];

NSBlockOperation*operation3 = [NSBlockOperationblockOperationWithBlock:^{

NSLog(@"operation3打印內(nèi)容:3333333");

}];

//[operation3 start];

//3苍日、創(chuàng)建任務(wù)隊(duì)列

NSOperationQueue*q = [[NSOperationQueuealloc]init];

//給添加入隊(duì)列中的線程排序:即隊(duì)列中添加依賴關(guān)系

[operation1addDependency:operation];

[operation2addDependency:operation1];

[operation3addDependency:operation2];

[qaddOperation:operation];

[qaddOperation:operation1];

[qaddOperation:operation2];

[qaddOperation:operation3];

[qsetMaxConcurrentOperationCount:1];//設(shè)置隊(duì)列的最大并行數(shù);為1為串行隊(duì)列窗声;

NSLog(@"主線程中打印的內(nèi)容");

//5相恃、延后一段時(shí)間執(zhí)行某個(gè)任務(wù),兩種方法笨觅,優(yōu)選第二種方法:

//[self performSelector:@selector(yanHouTime) withObject:nil afterDelay:1];

dispatch_time_ttime =dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 *NSEC_PER_SEC));

dispatch_after(time,dispatch_get_main_queue(), ^{

NSLog(@"用GCD延后時(shí)間執(zhí)行某個(gè)任務(wù)");

});

}

-(void)operationDaYin

{

NSLog(@"operation的打印內(nèi)容:00000000000");

}

-(void)log:(NSString*)str

{

NSLog(@"子線程傳給主線程的值:%@",str);

}

-(void)yanHouTime

{

NSLog(@"用perform方法延后時(shí)間再執(zhí)行某個(gè)任務(wù)");

}


第7章系統(tǒng)框架

第47條:熟悉系統(tǒng)框架

1)許多系統(tǒng)框架都可以直接使用拦耐。其中最重要的是Foundation與CoreFoundation耕腾,這兩個(gè)框架提供了構(gòu)建應(yīng)用程序所需要的許多核心功能;

2)很多常見(jiàn)任務(wù)都能用框架來(lái)做杀糯,例如音頻與視頻處理扫俺、網(wǎng)絡(luò)通信、數(shù)據(jù)管理等固翰;

3)請(qǐng)記桌俏场:用純C寫(xiě)成的框架與用Objective-C寫(xiě)成的一樣重要,若想成為優(yōu)秀的Objective-C開(kāi)發(fā)者倦挂,應(yīng)該掌握C語(yǔ)言的核心概念畸颅;

第48條:多用塊枚舉,少用for循環(huán)

1)遍歷collection有四種方式方援。最基本的辦法是for循環(huán)没炒,其次是NSEnumerator遍歷法及快速遍歷法,最新犯戏、最先進(jìn)的方式是“塊枚舉法”送火;

2)“塊枚舉法”本身就能通過(guò)GCD來(lái)并發(fā)執(zhí)行遍歷操作,無(wú)須另行編寫(xiě)代碼先匪。而采用其他遍歷方式則無(wú)法輕易實(shí)現(xiàn)這一點(diǎn)种吸;

3)若提前知道待遍歷的collection含有何種對(duì)象,則應(yīng)修改塊簽名呀非,指出對(duì)象的具體類型坚俗;

第49條:對(duì)自定義其內(nèi)存管理語(yǔ)義的collection使用無(wú)縫橋接

1)通過(guò)無(wú)縫橋接技術(shù),可以再Foundation框架中的Objective-C對(duì)象與CoreFoundation框架中的C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之間來(lái)回轉(zhuǎn)換岸裙;

2)在CoreFoundation層面創(chuàng)建collection時(shí)猖败,可以指定許多回調(diào)函數(shù),這些函數(shù)表示此collection應(yīng)如何處理其元素降允。然后恩闻,可運(yùn)用無(wú)縫橋接技術(shù),將其轉(zhuǎn)換成具備特殊內(nèi)存管理語(yǔ)義的Objective-C collection剧董;

第50條:構(gòu)建緩存時(shí)選用NSCache而非NSDictionary

1)實(shí)現(xiàn)緩存時(shí)應(yīng)選用NSCache而非NSDictionary對(duì)象幢尚。因?yàn)镹SCache可以提供優(yōu)雅的自動(dòng)刪除功能,而且是“線程安全的”翅楼,此外尉剩,它與字典不同,并不會(huì)拷貝鍵毅臊;

2)可以給NSCache對(duì)象設(shè)置上限理茎,用以限制緩存中的對(duì)象總個(gè)數(shù)及“總成本”,而這些尺度則定義了緩存刪減其中對(duì)象的時(shí)機(jī)。但是絕對(duì)不要把這些尺度當(dāng)成可靠的“硬限制”(hard limit)功蜓,它們僅對(duì)NSCache起指導(dǎo)作用;

3)將NSPurgeableData與NSCache搭配使用宠蚂,可實(shí)現(xiàn)自動(dòng)清除數(shù)據(jù)的功能式撼,也就是說(shuō),當(dāng)NSPurgeableData對(duì)象所占內(nèi)存為系統(tǒng)丟棄時(shí)求厕,該對(duì)象自身也會(huì)從緩存中移除著隆;

4)如果緩存使用得當(dāng),那么應(yīng)用程序的響應(yīng)速度就能提高呀癣。只有那種“重新計(jì)算起來(lái)很費(fèi)事的”數(shù)據(jù)美浦,才值得放入緩存,比如那些需要從網(wǎng)絡(luò)獲取或從磁盤(pán)讀取的數(shù)據(jù)项栏;

第51條:精簡(jiǎn)initialize與load的實(shí)現(xiàn)代碼(很少用這兩個(gè)類方法)

1)在加載階段浦辨,如果類實(shí)現(xiàn)了load方法,那么系統(tǒng)就會(huì)調(diào)用它沼沈。分類里也可以定義此方法流酬,類的load方法要比分類中的先調(diào)用。與其他方法不同列另,load方法不參與覆寫(xiě)機(jī)制芽腾。

2)首次使用某個(gè)類之前,系統(tǒng)會(huì)向其發(fā)送initialize消息页衙。由于此方法遵從普通的覆寫(xiě)規(guī)則摊滔,所以通常應(yīng)該在里面判斷當(dāng)前要初始化的是哪個(gè)類;

3)load與initialize方法都應(yīng)該實(shí)現(xiàn)得精簡(jiǎn)一些店乐,這有助于保持應(yīng)用程序的響應(yīng)能力艰躺,也能減少引入“依賴環(huán)(interdependency cycle)”的幾率;

4)無(wú)法在編譯期設(shè)定的全局變量响巢,可以放在initialize方法里初始化描滔;

第52條:別忘了NSTimer會(huì)保留其目標(biāo)對(duì)象

1)NSTimer對(duì)象會(huì)保留其目標(biāo),直到計(jì)時(shí)器本身失效為止踪古,調(diào)用invalidate方法可令計(jì)時(shí)器失效含长,另外,一次性的計(jì)時(shí)器在觸發(fā)完任務(wù)之后也會(huì)失效伏穆;

2)反復(fù)執(zhí)行任務(wù)的計(jì)時(shí)器(repeating timer)拘泞,很容易引入保留環(huán),如果這種計(jì)時(shí)器的目標(biāo)對(duì)象又保留了計(jì)時(shí)器本身枕扫,那肯定會(huì)導(dǎo)致保留環(huán)陪腌。這種環(huán)狀保留關(guān)系,可能是直接發(fā)生的,也可能是通過(guò)對(duì)象里的其他對(duì)象間接發(fā)生的诗鸭;

3)可以擴(kuò)充NSTimer的功能染簇,用“塊”來(lái)打破保留環(huán)。不過(guò)强岸,除非NSTimer將來(lái)在公共接口里提供此功能锻弓,否則必須創(chuàng)建分類,將相關(guān)實(shí)現(xiàn)代碼加入其中蝌箍;

//防止反復(fù)執(zhí)行的計(jì)時(shí)器引入“保留環(huán)”方法

__weakViewController*weakSelf =self;

NSTimer*timer = [selflzw_scheduledTimerWithTimeInterval:1block:^{

NSLog(@"運(yùn)用block塊進(jìn)行計(jì)時(shí)器循環(huán)************");

[weakSelfdoSomeThing];

}repeats:YES];

-(void)doSomeThing

{

NSLog(@"111111111111111111");

}

-(NSTimer*)lzw_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats

{

return[NSTimerscheduledTimerWithTimeInterval:intervaltarget:selfselector:@selector(lzw_blockInvoke:)userInfo:[blockcopy]repeats:YES];

}

-(void)lzw_blockInvoke:(NSTimer*)timer

{

void(^block)() = timer.userInfo;

if(block) {

block();

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末青灼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妓盲,更是在濱河造成了極大的恐慌杂拨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悯衬,死亡現(xiàn)場(chǎng)離奇詭異弹沽,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)筋粗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)贷币,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人亏狰,你說(shuō)我怎么就攤上這事役纹。” “怎么了暇唾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵促脉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我策州,道長(zhǎng)瘸味,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任够挂,我火速辦了婚禮旁仿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘孽糖。我一直安慰自己枯冈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布办悟。 她就那樣靜靜地躺著尘奏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪病蛉。 梳的紋絲不亂的頭發(fā)上炫加,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天瑰煎,我揣著相機(jī)與錄音,去河邊找鬼俗孝。 笑死酒甸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赋铝。 我是一名探鬼主播烘挫,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柬甥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起其垄,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤苛蒲,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后绿满,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體臂外,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年喇颁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漏健。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡橘霎,死狀恐怖蔫浆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姐叁,我是刑警寧澤瓦盛,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站外潜,受9級(jí)特大地震影響原环,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜处窥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一嘱吗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滔驾,春花似錦谒麦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至沽瞭,卻和暖如春迁匠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工城丧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留延曙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓亡哄,卻偏偏與公主長(zhǎng)得像枝缔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚊惯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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