ios rumtime 1- 類與對象

本文是參考南峰子Objective-C Runtime系列文章
做一個自己的總結(jié)褒翰,強烈推薦查看原文

1、runtime介紹

Objective-C 是一門動態(tài)語言楚里,它將很多靜態(tài)語言在編譯和連接時期做的事情放到了運行時來處理断部,這種動態(tài)語言的優(yōu)勢在于:我們寫代碼時更具有靈活性,如我們可以把消息轉(zhuǎn)發(fā)給我們想要轉(zhuǎn)發(fā)的對象班缎,或者隨意交換一個方法等蝴光。

這種特性意味著Objective-C不僅需要一個編譯器,還需要一個運行時動態(tài)庫來執(zhí)行編譯的代碼达址。對于Objective-C來說蔑祟,這個運行時系統(tǒng)就像一個操作系統(tǒng)一樣:讓所有工作正常運行。這個運行時系統(tǒng)就是Objc Runtime 沉唠,Objc Runtime其實是一個Runtime庫疆虚,基本上是用C語言匯編語言寫的,使得C語言有了面向?qū)ο蟮哪芰Α?/p>

Runtime庫主要做了以下兩件事:

  1. 封裝:在這個庫中,對象可以使用C語言中的結(jié)構(gòu)體表示径簿,方法可以使用C函數(shù)來實現(xiàn)罢屈,另外再加上一些額外的特性,這些結(jié)構(gòu)體和函數(shù)被runtime函數(shù)封裝后篇亭,我們就可以在程序運行時創(chuàng)建缠捌、檢查、修改類译蒂、對象鄙币、方法了
  2. 找出方法的最終執(zhí)行代碼:當程序執(zhí)行[object doSomething]時,會向接受者(object)發(fā)送一條消息(doSomething)蹂随,runtime會根據(jù)消息接受者能否響應該消息而做出不同反應

Objective-C runtime目前有兩個版本:Modern runtimeLegacy runtimeModern Runtime覆蓋了64位的Mac OS X Apps因惭,還有iOS Apps岳锁,Legacy Runtime是早期用來給32位 Mac OS X Apps 用的,已經(jīng)過時

蘋果和GNU各自維護一個開源的 runtime 版本,這兩個版本之間都在努力的保持一致蹦魔。

高級編程語言想要成為可執(zhí)行文件激率,需要先編譯成匯編語言,再匯編為機器語言勿决,機器語言是計算機唯一能識別的語言(轉(zhuǎn)換過程待研究)

2乒躺、類

Objective-C類是有Class類型表示,實際上是指向objc_class結(jié)構(gòu)體的指針低缩,定義如下

typedef struct objc_class *Class;

objc_class定義如下

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父類
    const char *name                        OBJC2_UNAVAILABLE;  // 類名
    long version                            OBJC2_UNAVAILABLE;  // 類的版本信息嘉冒,默認為0
    long info                               OBJC2_UNAVAILABLE;  // 類信息,供運行期使用的一些位標識
    long instance_size                      OBJC2_UNAVAILABLE;  // 該類的實例變量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 該類的成員變量鏈表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;

1.isa : 需要注意的是在Objective-C中咆繁,所有的類自身也是一個對象讳推,這個對象的Class里面也有一個isa指針,它指向metaClass(元類)

  1. super_class :指向該類的父類玩般,如果該類已經(jīng)是最頂層的根類(如NSObjectNSProxy)银觅,則super_classNULL

  2. name : 類名

  3. version :我們可以使用這個字段來提供類的版本信息。這對于對象的序列化非常有用坏为,它可是讓我們識別出不同類定義版本中實例變量布局的改變究驴。

  4. info : 類信息

  5. instance_size : 該類的對象大小

  6. ivars : 成員變量的列表

  7. methodLists : 方法列表

  8. cathe : 用于緩存最近使用的方法。
    一個接收者對象接收到一個消息時匀伏,它會根據(jù)isa指針去查找能夠響應這個消息的對象洒忧。在實際使用中,這個對象只有一部分方法是常用的帘撰,很多方法其實很少用或者根本用不上跑慕。這種情況下,如果每次消息來時,我們都是methodLists中遍歷一遍核行,性能勢必很差牢硅。這時,cache就派上用場了芝雪。在我們每次調(diào)用過一個方法后减余,這個方法就會被緩存到cache列表中,下次調(diào)用的時候runtime就會優(yōu)先去cache中查找惩系,如果cache沒有位岔,才去methodLists中查找方法。這樣堡牡,對于那些經(jīng)常用到的方法的調(diào)用抒抬,提高了調(diào)用的效率。

  9. protocols : 協(xié)議列表

3晤柄、對象

objc_object是表示一個類的實例的結(jié)構(gòu)體

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};

這個結(jié)構(gòu)體只有一個屬性擦剑,即指向其類的isa指針。這樣芥颈,當我們向一個Objective-C對象發(fā)送消息時惠勒,運行時庫會根據(jù)實例對象的isa指針找到這個實例對象所屬的類。Runtime庫會在類的方法列表及父類的方法列表中去尋找與消息對應的selector指向的方法,找到后即運行這個方法爬坑。

4纠屋、元類(Meta Class)

meta-class是一個類對象的類

當我們向一個對象發(fā)送消息時,runtime會在這個對象所屬的這個類的方法列表中查找方法盾计;
而向一個類發(fā)送消息時售担,會在這個類的meta-class的方法列表中查找方法

meta-class之所以重要,是因為它存儲著一個類的所有類方法署辉。每個類都會有一個單獨的meta-class灼舍,因為每個類的類方法基本不可能完全相同

meta-class也是一個類,也可以向它發(fā)送一個消息涨薪,那么它的isa又是指向什么呢骑素?為了不讓這種結(jié)構(gòu)無限延伸下去,Objective-C的設(shè)計者讓所有的meta-classisa指向基類的meta-class刚夺,以此作為它們的所屬類献丑。
即,任何NSObject繼承體系下的meta-class都使用NSObjectmeta-class作為自己的所屬類侠姑,而基類的meta-classisa指針是指向它自己创橄。這樣就形成了一個完美的閉環(huán)。

Class和meta-Class.png

對于NSObject繼承體系來說莽红,其實例方法對體系中的所有實例妥畏、類和meta-class都是有效的邦邦;而類方法對于體系內(nèi)的所有類和meta-class都是有效的。

5醉蚁、objc_cache

cathe用于緩存調(diào)用過的方法燃辖。這個字段是一個指向objc_cache結(jié)構(gòu)體的指針,其定義如下:

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method _Nullable buckets[1]                              OBJC2_UNAVAILABLE;
};
  1. mask:一個整數(shù)网棍,指定分配的緩存bucket的總數(shù)黔龟。在方法查找過程中,runtime使用這個字段來確定開始線性查找數(shù)組的索引位置滥玷。指向方法selector的指針與該字段做一個AND位操作(index = (mask & selector))氏身。這可以作為一個簡單的hash散列算法。
  2. occupied:一個整數(shù)惑畴,指定實際占用的緩存bucket的總數(shù)蛋欣。
  3. buckets:指向Method數(shù)據(jù)結(jié)構(gòu)指針的數(shù)組。這個數(shù)組可能包含不超過mask+1個元素如贷。需要注意的是豁状,指針可能是NULL,表示這個緩存bucket沒有被占用倒得,另外被占用的bucket可能是不連續(xù)的。這個數(shù)組可能會隨著時間而增長夭禽。

6霞掺、類與對象的操作函數(shù)

類的操作方法大部分是以class_為前綴的
對象的操作方法大部分是以objc_object_為前綴

runtime.h里面搜索Working with ,一共有8個搜索結(jié)果讹躯,搜索順序分別是:

  1. Working with Instances
  2. Working with Classes
  3. Working with Methods
  4. Working with Instance Variables
  5. Working with Properties
  6. Working with Protocols
  7. Working with Libraries
  8. Working with Selectors

這里我們主要看Working with Classes菩彬、Working with InstancesWorking with Instance Variables里面的方法

6.1潮梯、動態(tài)創(chuàng)建類

//創(chuàng)建一個新類和元類
Class objc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name, 
                       size_t extraBytes) ;

// 在應用中注冊由objc_allocateClassPair創(chuàng)建的類
void objc_registerClassPair(Class _Nonnull cls) ;

//銷毀一個類極其相關(guān)類
Class objc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,
                    size_t extraBytes);

  1. objc_allocateClassPair函數(shù):如果我們要創(chuàng)建一個根類骗灶,則superclass指定為NilextraBytes通常指定為0秉馏,該參數(shù)是分配給類和元類對象尾部的索引ivars的字節(jié)數(shù)耙旦。

  2. objc_disposeClassPair函數(shù)用于銷毀一個類,不過需要注意的是萝究,如果程序運行中還存在類或其子類的實例免都,則不能調(diào)用針對類調(diào)用該方法。

創(chuàng)建一個新類,先用objc_allocateClassPair,調(diào)用class_addMethod帆竹,class_addIvar等函數(shù)來為新創(chuàng)建的類添加方法绕娘、實例變量和屬性等。再調(diào)用objc_registerClassPair函數(shù)來注冊類栽连,之后這個新類就可以在程序中使用了险领。

實例方法和實例變量應該添加到類自身上侨舆,而類方法應該添加到類的元類上

6.2、動態(tài)創(chuàng)建對象

// 創(chuàng)建類實例
id class_createInstance ( Class cls, size_t extraBytes );
// 在指定位置創(chuàng)建類實例
id objc_constructInstance ( Class cls, void *bytes );
// 銷毀類實例
void * objc_destructInstance ( id obj );
  1. class_createInstance :創(chuàng)建實例時绢陌,會在默認的內(nèi)存區(qū)域為類分配內(nèi)存挨下。extraBytes額外的字節(jié)可以用來存儲類定義中定義之外的其他實例變量.

  2. objc_constructInstance :在指定的位置(bytes)創(chuàng)建類實例。

  3. objc_destructInstance:銷毀一個類的實例下面,但不會釋放并移除任何與其相關(guān)的引用复颈。

類和對象的相關(guān)操作函數(shù)

// 返回指定對象的一份拷貝
id object_copy ( id obj, size_t size );

// 釋放指定對象占用的內(nèi)存
id object_dispose ( id obj );

// 修改類實例的實例變量的值
Ivar object_setInstanceVariable ( id obj, const char *name, void *value );

// 獲取對象實例變量的值
Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue );

// 返回指向給定對象分配的任何額外字節(jié)的指針
void * object_getIndexedIvars ( id obj );

// 返回對象中實例變量的值
id object_getIvar ( id obj, Ivar ivar );

// 設(shè)置對象中實例變量的值
void object_setIvar ( id obj, Ivar ivar, id value );

// 返回給定對象的類名
const char * object_getClassName ( id obj );

// 返回對象的類
Class object_getClass ( id obj );

// 設(shè)置對象的類
Class object_setClass ( id obj, Class cls );

// 獲取已注冊的類定義的列表
int objc_getClassList ( Class *buffer, int bufferCount );

// 創(chuàng)建并返回一個指向所有已注冊類的指針列表
Class * objc_copyClassList ( unsigned int *outCount );

// 返回指定類的類定義
Class objc_lookUpClass ( const char *name );
Class objc_getClass ( const char *name );
Class objc_getRequiredClass ( const char *name );

// 返回指定類的元類
Class objc_getMetaClass ( const char *name );

6.3、父類(super_class)和元類(meta-class)

// 獲取類的父類
Class class_getSuperclass (Class _Nullable cls);

// 判斷給定的Class是否是一個元類
BOOL class_isMetaClass (Class _Nullable cls);

6.4沥割、類名

// 獲取類的類名
const char * class_getName (Class _Nullable cls);

6.5耗啦、版本號

// 獲取版本號
int class_getVersion (Class _Nullable cls) ;

// 設(shè)置版本號
void class_setVersion (Class _Nullable cls, int version);

6.6、實例大小

// 獲取實例大小
size_t class_getInstanceSize (Class _Nullable cls);

6.7 成員變量

// 獲取類中指定名稱實例成員變量的信息
Ivar class_getInstanceVariable (Class _Nullable cls, const char * _Nonnull name)机杜; 

// 獲取類成員變量的信息
Ivar class_getClassVariable(Class _Nullable cls, const char * _Nonnull name);

// 添加成員變量
BOOL class_addIvar (Class _Nullable cls, const char * _Nonnull name, size_t size, 
              uint8_t alignment, const char * _Nullable types) ;

// 獲取整個成員變量列表
Ivar * class_copyIvarList (Class _Nullable cls, unsigned int * _Nullable outCount) ;
  1. class_getInstanceVariable: 根據(jù)name返回指定的對象成員變量信息(objc_ivar結(jié)構(gòu)體)
  1. class_getClassVariable: 根據(jù)name返回指定的類成員變量信息(objc_ivar結(jié)構(gòu)體)帜讲,一般認為Objective-C不支持類變量

  2. class_addIvar : 參數(shù)分別是,成員變量所屬類椒拗、成員變量名似将、對齊方式、成員變量類型

Objective-C不支持往已存在的類中添加實例成員變量蚀苛,因此不管是系統(tǒng)庫提供的提供的類在验,還是我們自定義的類,都無法動態(tài)添加成員變量,但是動態(tài)創(chuàng)建類的可以添加成員變量堵未,只能在objc_allocateClassPairobjc_registerClassPair之間

如添加一個NSString類型的ivar1變量

class_addIvar(cls, "ivar1", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
  1. class_copyIvarList : 它返回一個指向成員變量信息的數(shù)組腋舌,數(shù)組中每個元素是指向該成員變量信息的objc_ivar結(jié)構(gòu)體的指針,outCount指針返回數(shù)組的大小

注意 : 返回的列表不包含父類的成員變量和屬性渗蟹,必須使用free()來釋放這個數(shù)組

6.8 屬性

// 獲取指定的屬性
objc_property_t class_getProperty(Class _Nullable cls, const char * _Nonnull name);

// 獲取屬性列表
objc_property_t  class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount);

// 為類添加屬性
BOOL class_addProperty(Class _Nullable cls, const char * _Nonnull name,
                  const objc_property_attribute_t * _Nullable attributes,
                  unsigned int attributeCount);

// 替換類的屬性
void class_replaceProperty(Class _Nullable cls, const char * _Nonnull name,
                      const objc_property_attribute_t * _Nullable attributes,
                      unsigned int attributeCount)

  1. class_getProperty : 根據(jù)name返回指定的類屬性(objc_property結(jié)構(gòu)體)
  2. class_copyPropertyList : 它返回一個指向?qū)傩缘臄?shù)組块饺,數(shù)組中每個元素是指向該屬性的objc_property結(jié)構(gòu)體的指針,outCount指針返回數(shù)組的大小

注意 : 返回的列表不包含父類的屬性雌芽,必須使用free()來釋放這個數(shù)組

  1. class_addProperty : 參數(shù)含義分別是:類名授艰、屬性名、屬性特性世落、屬性特性個數(shù)
    如添加屬性名為@property (nonatomic , copy) NSString *property1;的屬性
   objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "" }; // C = copy
    objc_property_attribute_t nonatomic = { "N", "" }; //nonatomic
    objc_property_attribute_t backingivar  = { "V", "_property1" };//V 實例變量
    objc_property_attribute_t attrs[] = { type, ownership,nonatomic, backingivar };
    class_addProperty(cls, "property1", attrs, 4);
  1. class_replaceProperty : 替換類的屬性

6.9淮腾、方法

//添加方法
BOOL class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                const char * _Nullable types);

//獲取實例方法
Method class_getInstanceMethod(Class _Nullable cls, SEL _Nonnull name);

//獲取類方法
Method class_getClassMethod(Class _Nullable cls, SEL _Nonnull name);

//獲取所有方法數(shù)組
Method  class_copyMethodList(Class _Nullable cls, unsigned int * _Nullable outCount);

//替代方法的實現(xiàn)
IMP class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
                    const char * _Nullable types) ;

//返回方法的具體實現(xiàn)
IMP class_getMethodImplementation(Class _Nullable cls, SEL _Nonnull name) ;
IMP class_getMethodImplementation_stret(Class _Nullable cls, SEL _Nonnull name) ;

//對象是否響應指定的selector
BOOL class_respondsToSelector(Class _Nullable cls, SEL _Nonnull sel) ;

1.class_addMethod : 參數(shù)含義分別是:添加方法的類、添加方法的編號屉佳、方法實現(xiàn)来破、方法類型,使用這個方法添加方法會覆蓋父類的方法實現(xiàn)忘古,但不會取代本類中已存在的實現(xiàn)徘禁,如果本類中包含一個同名的實現(xiàn),則函數(shù)會返回NO髓堪。如果要修改已存在實現(xiàn)送朱,可以使用method_setImplementation

如添加一個eat方法

class_addMethod([self class],@selector(eat:),(IMP) eatIMP, "v@:@");
  1. class_getInstanceMethod : 根據(jù)name返回指定的對象方法(objc_method結(jié)構(gòu)體)
  2. class_getClassMethod : 根據(jù)name返回指定的類方法(objc_method結(jié)構(gòu)體)

注意 : 這兩個函數(shù)都會去搜索父類的實現(xiàn)

  1. class_copyMethodList: 返回一個指向?qū)嵗椒ǖ臄?shù)組娘荡,數(shù)組中每個元素都是該方法信息的objc_method結(jié)構(gòu)體指針,outCount返回數(shù)組的大小驶沼。
    如果需要獲取類方法炮沐,則可以使用class_copyMethodList(object_getClass(cls), &count),因為一個類的實例方法是定義在元類里面

注意 : 返回的列表不包含父類的方法回怜,必須使用free()來釋放這個數(shù)組

  1. class_replaceMethod : 如果類中不存在name指定的方法大年,則類似于class_addMethod函數(shù)一樣會添加方法;如果類中已存在name指定的方法玉雾,則類似于method_setImplementation一樣替代原方法的實現(xiàn)翔试。

  2. class_getMethodImplementation : 返回一個指向方法實現(xiàn)函數(shù)的指針,在向類實例發(fā)送消息時會被調(diào)用,這個函數(shù)會比method_getImplementation(class_getInstanceMethod(cls, name))更快复旬。返回的函數(shù)指針可能是一個指向runtime內(nèi)部的函數(shù)垦缅,而不一定是方法的實際實現(xiàn)。例如驹碍,如果類實例無法響應selector壁涎,則返回的函數(shù)指針將是運行時消息轉(zhuǎn)發(fā)機制的一部分。

  3. class_respondsToSelector : 我們通常使用NSObject類的respondsToSelector:instancesRespondToSelector:方法來達到相同目的志秃。

6.10怔球、協(xié)議

// 添加協(xié)議
BOOL class_addProtocol ( Class cls, Protocol *protocol );
// 返回類是否實現(xiàn)指定的協(xié)議
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
// 返回類實現(xiàn)的協(xié)議列表
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );

  1. class_conformsToProtocol : 可以使用NSObject類的conformsToProtocol:方法來替代。

  2. class_copyProtocolList : 返回一個指向協(xié)議的數(shù)組浮还,數(shù)組中每個元素都是該協(xié)議信息的objc_object結(jié)構(gòu)體指針竟坛,outCount返回數(shù)組的大小。

注意 : 返回的列表不包含父類的協(xié)議碑定,必須使用free()來釋放這個數(shù)組

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市又官,隨后出現(xiàn)的幾起案子延刘,更是在濱河造成了極大的恐慌,老刑警劉巖六敬,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碘赖,死亡現(xiàn)場離奇詭異,居然都是意外死亡外构,警方通過查閱死者的電腦和手機普泡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來审编,“玉大人撼班,你說我怎么就攤上這事±莩辏” “怎么了砰嘁?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵件炉,是天一觀的道長。 經(jīng)常有香客問我矮湘,道長斟冕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任缅阳,我火速辦了婚禮磕蛇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘十办。我一直安慰自己秀撇,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布橘洞。 她就那樣靜靜地躺著捌袜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪炸枣。 梳的紋絲不亂的頭發(fā)上虏等,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音适肠,去河邊找鬼霍衫。 笑死,一個胖子當著我的面吹牛侯养,可吹牛的內(nèi)容都是我干的敦跌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼逛揩,長吁一口氣:“原來是場噩夢啊……” “哼柠傍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辩稽,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惧笛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后逞泄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體患整,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年喷众,在試婚紗的時候發(fā)現(xiàn)自己被綠了各谚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡到千,死狀恐怖昌渤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情憔四,我是刑警寧澤愈涩,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布望抽,位于F島的核電站,受9級特大地震影響履婉,放射性物質(zhì)發(fā)生泄漏煤篙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧进萄,春花似錦、人聲如沸鸠窗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稍计。三九已至,卻和暖如春裕循,著一層夾襖步出監(jiān)牢的瞬間臣嚣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工剥哑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留硅则,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓株婴,卻偏偏與公主長得像怎虫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子困介,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355