iOS底層原理--oc

在長(zhǎng)期iOS開發(fā)中际乘,oc是iOS的基礎(chǔ)也是重中之重,相比runtime井厌,runloop蚓庭,多線程等知識(shí)都要重要的多,更加深入的了解oc的知識(shí)仅仆,才能寫出加健壯的代碼

以下內(nèi)容器赞,摘自網(wǎng)絡(luò),如有版權(quán)墓拜,可以聯(lián)系港柜。

探尋OC對(duì)象的本質(zhì),我們平時(shí)編寫的Objective-C代碼咳榜,底層實(shí)現(xiàn)其實(shí)都是C\C++代碼夏醉。我們通過(guò)clang 將OC代碼轉(zhuǎn)為C\C++代碼

OC如下代碼

int main(int argc, char * argv[]) {
    @autoreleasepool {
        NSObject* objc = [[NSObject alloc] init];
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

我們通過(guò)clang命令行將OC的mian.m文件轉(zhuǎn)化為c++文件。

輸入指令要注意斜體位置的路徑是本機(jī)Xcode的路徑
clang -x objective-c -rewrite-objc -isysroot /Users/admin/Desktop/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m
補(bǔ)充下我的xcode位置在桌面所以是上面鏈接涌韩,正常的應(yīng)該是下面的clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m

.cpp文件添加進(jìn)入項(xiàng)目無(wú)法編譯運(yùn)行畔柔,需要去掉它


image.png

NSObject_IMPL內(nèi)部

typedef struct objc_class *Class;

struct NSObject_IMPL {
    Class isa;
};

NSObjcet的底層實(shí)現(xiàn),點(diǎn)擊NSObjcet進(jìn)入發(fā)現(xiàn)NSObject的內(nèi)部實(shí)現(xiàn)

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
@end

轉(zhuǎn)化為c語(yǔ)言其實(shí)就是一個(gè)結(jié)構(gòu)體

為了探尋OC對(duì)象在內(nèi)存中如何體現(xiàn)臣樱,我們來(lái)看下面一段代碼

NSObject* objc = [[NSObject alloc] init];

轉(zhuǎn)換后代碼

NSObject* objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)
                                ((NSObject *(*)(id, SEL))(void *)objc_msgSend)
                                ((id)objc_getClass("NSObject"), sel_registerName("alloc")), 
                                sel_registerName("init"));

上述一段代碼中系統(tǒng)為NSObject對(duì)象分配8個(gè)字節(jié)的內(nèi)存空間靶擦,用來(lái)存放一個(gè)成員isa指針。那么isa指針這個(gè)變量的地址就是結(jié)構(gòu)體的地址雇毫,也就是NSObjcet對(duì)象的地址玄捕。

獲取對(duì)象大小

class_getInstanceSize([NSObject class]);    // 8   返回的是對(duì)象的大小
malloc_size( (__bridge const void *)(objc));// 16  返回的是分配空間大小

oc分配對(duì)象大小源碼

    size_t instanceSize(size_t extraBytes) {
        size_t size = alignedInstanceSize() + extraBytes;
         //CF要求所有對(duì)象至少為16個(gè)字節(jié)。當(dāng)小于16后會(huì)分配16棚放。
        if (size < 16) size = 16;
        return size;
    }

那么這個(gè)結(jié)構(gòu)體占多大的內(nèi)存空間呢枚粘,我們發(fā)現(xiàn)這個(gè)結(jié)構(gòu)體只有一個(gè)成員,isa指針飘蚯,而指針在64位架構(gòu)中占8個(gè)字節(jié)馍迄。也就是說(shuō)一個(gè)NSObjec對(duì)象所占用的內(nèi)存是8個(gè)字節(jié)福也。

但是我們發(fā)現(xiàn)NSObject對(duì)象中還有很多方法,那這些方法不占用內(nèi)存空間嗎攀圈?其實(shí)類的方法等也占用內(nèi)存空間拟杉,但是這些方法所占用的存儲(chǔ)空間并不在NSObject對(duì)象中。

那跟復(fù)雜的繼承關(guān)系對(duì)象的大小是如何計(jì)算的


image.png

繼承自NSObject的對(duì)象量承,那么底層結(jié)構(gòu)體內(nèi)一定有一個(gè)isa指針。

那么他們所占的內(nèi)存空間是多少呢穴店?單純的將指針和成員變量所占的內(nèi)存相加即可嗎撕捍?上述代碼實(shí)際打印的內(nèi)容是16 16,也就是說(shuō)泣洞,person對(duì)象和student對(duì)象所占用的內(nèi)存空間都為16個(gè)字節(jié)忧风。
其實(shí)實(shí)際上person對(duì)象確實(shí)只使用了12個(gè)字節(jié)。但是因?yàn)閮?nèi)存對(duì)齊的原因球凰。使person對(duì)象也占用16個(gè)字節(jié)狮腿。

編譯器在給結(jié)構(gòu)體開辟空間時(shí),首先找到結(jié)構(gòu)體中最寬的基本數(shù)據(jù)類型呕诉,然后尋找內(nèi)存地址能是該基本數(shù)據(jù)類型的整倍的位置缘厢,作為結(jié)構(gòu)體的首地址。將這個(gè)最寬的基本數(shù)據(jù)類型的大小作為對(duì)齊模數(shù)甩挫。
為結(jié)構(gòu)體的一個(gè)成員開辟空間之前贴硫,編譯器首先檢查預(yù)開辟空間的首地址相對(duì)于結(jié)構(gòu)體首地址的偏移是否是本成員的整數(shù)倍,若是伊者,則存放本成員英遭,反之,則在本成員和上一個(gè)成員之間填充一定的字節(jié)亦渗,以達(dá)到整數(shù)倍的要求挖诸,也就是將預(yù)開辟空間的首地址后移幾個(gè)字節(jié)。
我們可以總結(jié)內(nèi)存對(duì)齊為兩個(gè)原則:
原則 1. 前面的地址必須是后面的地址正數(shù)倍,不是就補(bǔ)齊法精。
原則 2. 整個(gè)Struct的地址必須是最大字節(jié)的整數(shù)倍多律。

通過(guò)上述內(nèi)存對(duì)齊的原則我們來(lái)看,person對(duì)象的第一個(gè)地址要存放isa指針需要8個(gè)字節(jié)亿虽,第二個(gè)地址要存放_(tái)age成員變量需要4個(gè)字節(jié)菱涤,根據(jù)原則一,8是4的整數(shù)倍洛勉,符合原則一粘秆,不需要補(bǔ)齊。然后檢查原則2收毫,目前person對(duì)象共占據(jù)12個(gè)字節(jié)的內(nèi)存攻走,不是最大字節(jié)數(shù)8個(gè)字節(jié)的整數(shù)倍殷勘,所以需要補(bǔ)齊4個(gè)字節(jié),因此person對(duì)象就占用16個(gè)字節(jié)空間昔搂。

而對(duì)于student對(duì)象玲销,我們知道sutdent對(duì)象中,包含person對(duì)象的結(jié)構(gòu)體實(shí)現(xiàn)摘符,和一個(gè)int類型的_no成員變量贤斜,同樣isa指針8個(gè)字節(jié),_age成員變量4個(gè)字節(jié)逛裤,_no成員變量4個(gè)字節(jié)瘩绒,剛好滿足原則1和原則2,所以student對(duì)象占據(jù)的內(nèi)存空間也是16個(gè)字節(jié)带族。

對(duì)象alloc的流程圖锁荔,以及調(diào)用方法

圖片來(lái)自網(wǎng)絡(luò)
+ (id)alloc {
    return _objc_rootAlloc(self);
}

_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (slowpath(checkNil && !cls)) return nil;

#if __OBJC2__
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        // No alloc/allocWithZone implementation. Go straight to the allocator.
        // fixme store hasCustomAWZ in the non-meta class and 
        // add it to canAllocFast's summary
        if (fastpath(cls->canAllocFast())) {
            // No ctors, raw isa, etc. Go straight to the metal.
            bool dtor = cls->hasCxxDtor();
            id obj = (id)calloc(1, cls->bits.fastInstanceSize());
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            obj->initInstanceIsa(cls, dtor);
            return obj;
        }
        else {
            // Has ctor or raw isa or something. Use the slower path.
            id obj = class_createInstance(cls, 0);
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            return obj;
        }
    }
#endif

    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}

// Replaced by ObjectAlloc
+ (id)allocWithZone:(struct _NSZone *)zone {
    return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);
}


id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
    id obj;

#if __OBJC2__
    // allocWithZone under __OBJC2__ ignores the zone parameter
    (void)zone;
    obj = class_createInstance(cls, 0);
#else
    if (!zone) {
        obj = class_createInstance(cls, 0);
    }
    else {
        obj = class_createInstanceFromZone(cls, 0, zone);
    }
#endif

    if (slowpath(!obj)) obj = callBadAllocHandler(cls);
    return obj;
}

id
class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
{
    return _class_createInstanceFromZone(cls, extraBytes, zone);
}


static __attribute__((always_inline)) 
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
    if (!cls) return nil;

    assert(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size);
        if (!obj) return nil;
        obj->initInstanceIsa(cls, hasCxxDtor);
    } 
    else {
        if (zone) {
            obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (!obj) return nil;

        // Use raw pointer isa on the assumption that they might be 
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

    if (cxxConstruct && hasCxxCtor) {
        obj = _objc_constructOrFree(obj, cls);
    }

    return obj;
}


可以使用斷點(diǎn),Debug Workflow -> viewMemory address中輸入isa的地址去驗(yàn)證上述所說(shuō)
或者 memory read + 對(duì)象地址 或者x +地址 或x/(數(shù)量+格式+字節(jié)數(shù)) +地址(格式x是16進(jìn)制 f是浮點(diǎn) d十進(jìn)制 字節(jié)大小b:byte 1字節(jié) h:half word 2字節(jié) w:word 4字節(jié) g:giant word 8字節(jié))例

momory write + 地址+數(shù)據(jù) (方便調(diào)試)

image.png
image.png

同時(shí)需要理解一句話蝙砌,isa地址是結(jié)構(gòu)體首地址阳堕,即結(jié)構(gòu)體地址,這個(gè)理解下择克,后面要用
關(guān)于內(nèi)存對(duì)其相關(guān)知識(shí)

補(bǔ)充編譯器在給結(jié)構(gòu)體開辟空間時(shí)恬总,首先找到結(jié)構(gòu)體中最寬的基本數(shù)據(jù)類型,然后尋找內(nèi)存地址能是該基本數(shù)據(jù)類型的整倍的位置肚邢,作為結(jié)構(gòu)體的首地址越驻。將這個(gè)最寬的基本數(shù)據(jù)類型的大小作為對(duì)齊模數(shù)

補(bǔ)充結(jié)構(gòu)體首地址的偏移是否是本成員的整數(shù)倍道偷,若是缀旁,則存放本成員,反之勺鸦,則在本成員和上一個(gè)成員之間填充一定的字節(jié)并巍,以達(dá)到整數(shù)倍的要求,也就是將預(yù)開辟空間的首地址后移幾個(gè)字節(jié)换途。

(換句話說(shuō)懊渡,結(jié)構(gòu)體大小必須是最大成員的倍數(shù))

iOS 是小端 從高地址開始讀取數(shù)據(jù)

接著來(lái)看下oc對(duì)象的信息如何存放的

注意一個(gè)寫法oc對(duì)象->一個(gè)屬性。 t1->_name(通過(guò)指針直接訪問(wèn)成員變量)

蘋果在解釋oc的時(shí)候給出過(guò)一個(gè)圖表

image

在這張圖表中instance對(duì)象(實(shí)例對(duì)象)class對(duì)象(類對(duì)象)meta-class對(duì)象(元類對(duì)象)

instance 是由alloc方法生成的 军拟,每次調(diào)用alloc都會(huì)產(chǎn)生新的instance對(duì)象剃执。在寫單利時(shí)候要清楚這件事

說(shuō)下alloc和init

alloc方法生成懸掛指針,他指向一個(gè)新的內(nèi)存地址懈息,并將其持有返回地址給指針,所以每次調(diào)用都會(huì)生成新的對(duì)象肾档,在沒(méi)有進(jìn)行init的時(shí)候不建議使用,因?yàn)闆](méi)有合理的內(nèi)存布局

同時(shí)我們需要思考調(diào)用alloc后內(nèi)存是直接映射到堆還是只分配給了虛擬內(nèi)存

而init是在為內(nèi)存地址進(jìn)行初始化,但是init不一定是在alloc產(chǎn)生的內(nèi)存上進(jìn)行的初始化怒见,有可能是在新的內(nèi)存上原因在[super init]

在block被當(dāng)作屬性使用時(shí)俗慈,特別是在多線程中一定要判斷屬性是否為空

iOS里的內(nèi)存是有分類的,它分成Clean Memory和Dirty Memory遣耍。顧名思義闺阱,Clean Memory是可以被操作系統(tǒng)回收的,Dirty Memory是不可被操作系統(tǒng)回收的舵变。

Clean Memory:在閃存中有備份酣溃,能再次讀取重建。如:Code(代碼段),framework揍诽,memory-mapped files

Dirty Memory:所有非Clean Memory,如:被分配了的堆空間,image cache

例如

image

對(duì)每行分析:

1.Dirty Memory徊哑。

因?yàn)閟tringWithString:是在堆上分配內(nèi)存的,如果我們不回收它的話闪檬,系統(tǒng)會(huì)一直占用這塊內(nèi)存惜索。

2.Clean Memory。

因?yàn)橛眠@樣的方法創(chuàng)建的是一個(gè)常量字符串黔姜,常量字符串是放在只讀數(shù)據(jù)段的拢切,如果這塊內(nèi)存被釋放了,而我們又訪問(wèn)它的時(shí)候秆吵,操作系統(tǒng)可以在只讀數(shù)據(jù)段中把值再讀取出來(lái)重建這塊內(nèi)存淮椰。(所以用這種方法創(chuàng)建的string是沒(méi)有引用計(jì)數(shù)的。)

3.Clean Memory纳寂。

這個(gè)時(shí)候buf指向的100M內(nèi)存區(qū)域是Clean Memory的主穗,因?yàn)?strong>操作系統(tǒng)是很懶的,只有當(dāng)我們要用到這塊區(qū)域的時(shí)候才會(huì)映射到物理內(nèi)存毙芜,沒(méi)有使用的時(shí)候只會(huì)分配一塊虛擬內(nèi)存給buf忽媒。

image

可以看到虛擬內(nèi)存和物理內(nèi)存沒(méi)有映射關(guān)系,所以是Clean Memory的腋粥。

4.Dirty & Clean Memory混合晦雨。

前3M是Dirty Memory,后97M是Clean Memory隘冲。這句for語(yǔ)句執(zhí)行完成后闹瞧,buf的前3M內(nèi)存被賦值,也就是buf的前3M被使用了展辞,所以這個(gè)時(shí)候的映射關(guān)系是這樣的:

image

alloc不只分配在虛擬內(nèi)存奥邮,同時(shí)會(huì)在物理內(nèi)存建立映射。

iOS7過(guò)后部分蘋果機(jī)就開始從32位操作系統(tǒng)轉(zhuǎn)到64位了

關(guān)于內(nèi)存可以看https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MemoryAlloc.html

回歸主線

class對(duì)象 我們通過(guò)class方法或runtime方法得到一個(gè)class對(duì)象罗珍。class對(duì)象也就是類對(duì)象

Class Class1 = [object class];
// runtimeClass 
objectClass = object_getClass(object);

相同的類的類對(duì)象在內(nèi)存中只有一個(gè),class對(duì)象在內(nèi)存中存儲(chǔ)的信息主要包括 isa指針 superclass指針 類的屬性信息(@property)漠烧,類的成員變量信息(ivar)類的對(duì)象方法信息(instance method)杏愤,類的協(xié)議信息(protocol)

成員變量的值時(shí)存儲(chǔ)在實(shí)例對(duì)象中的,因?yàn)橹挥挟?dāng)我們創(chuàng)建實(shí)例對(duì)象的時(shí)候才為成員變賦值已脓。但是成員變量叫什么名字珊楼,是什么類型,只需要有一份就可以了度液。所以存儲(chǔ)在class對(duì)象中厕宗。

元類對(duì)象 meta-class

image

meta-class對(duì)象和class對(duì)象的內(nèi)存結(jié)構(gòu)是一樣的,但是用途不一樣堕担,在內(nèi)存中存儲(chǔ)的信息主要包括isa指針 superclass指針 類的類方法的信息(class method)所以meta-class中也有類的屬性信息已慢,類的對(duì)象方法信息等成員變量,但是其中的值可能是空的霹购。

對(duì)象的isa指針指向哪里
當(dāng)對(duì)象調(diào)用實(shí)例方法的時(shí)候佑惠,我們上面講到,實(shí)例方法信息是存儲(chǔ)在class類對(duì)象中的齐疙,那么要想找到實(shí)例方法膜楷,就必須找到class類對(duì)象,那么此時(shí)isa的作用就來(lái)了贞奋。

[oc ocMethod];
instance的isa指向class赌厅,當(dāng)調(diào)用對(duì)象方法時(shí),通過(guò)instance的isa找到class轿塔,最后找到對(duì)象方法的實(shí)現(xiàn)進(jìn)行調(diào)用特愿。

當(dāng)類對(duì)象調(diào)用類方法的時(shí)候,同上勾缭,類方法是存儲(chǔ)在meta-class元類對(duì)象中的揍障。那么要找到類方法,就需要找到meta-class元類對(duì)象俩由,而class類對(duì)象的isa指針就指向元類對(duì)象

[NSObjc NSObjcClassMethod];
class的isa指向meta-class當(dāng)調(diào)用類方法時(shí)亚兄,通過(guò)class的isa找到meta-class,最后找到類方法的實(shí)現(xiàn)進(jìn)行調(diào)用

同理 當(dāng)t1的instance對(duì)象要調(diào)用父類t的對(duì)象方法時(shí)采驻,會(huì)先通過(guò)isa找到t1的class审胚,然后通過(guò)superclass找到t的class,最后找到對(duì)象方法的實(shí)現(xiàn)進(jìn)行調(diào)用礼旅,同樣如果t發(fā)現(xiàn)自己沒(méi)有響應(yīng)的對(duì)象方法膳叨,又會(huì)通過(guò)Person的superclass指針找到NSObject的class對(duì)象,去尋找響應(yīng)的方法

當(dāng)類對(duì)象調(diào)用父類的類方法時(shí)痘系,就需要先通過(guò)isa指針找到meta-class菲嘴,然后通過(guò)superclass去尋找響應(yīng)的方法

對(duì)isa、superclass總結(jié)

instance的isa指向class,class的isa指向meta-class,meta-class的isa指向基類的meta-class,基類的isa指向自己,class的superclass指向父類的class龄坪,如果沒(méi)有父類昭雌,superclass指針為nil,meta-class的superclass指向父類的meta-class,基類的meta-class的superclass指向基類的class,instance調(diào)用對(duì)象方法的軌跡健田,isa找到class烛卧,方法不存在,就通過(guò)superclass找父類,class調(diào)用類方法的軌跡:isa找meta-class妓局,方法不存在总放,就通過(guò)superclass找父類注意最后沒(méi)找到會(huì)找到類的實(shí)例方法中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末好爬,一起剝皮案震驚了整個(gè)濱河市局雄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌存炮,老刑警劉巖炬搭,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異穆桂,居然都是意外死亡宫盔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門充尉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人衣形,你說(shuō)我怎么就攤上這事驼侠。” “怎么了谆吴?”我有些...
    開封第一講書人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵倒源,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我句狼,道長(zhǎng)笋熬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任腻菇,我火速辦了婚禮胳螟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筹吐。我一直安慰自己糖耸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開白布丘薛。 她就那樣靜靜地躺著嘉竟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舍扰,一...
    開封第一講書人閱讀 52,874評(píng)論 1 314
  • 那天倦蚪,我揣著相機(jī)與錄音,去河邊找鬼边苹。 笑死陵且,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勾给。 我是一名探鬼主播滩报,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼播急!你這毒婦竟也來(lái)了脓钾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桩警,失蹤者是張志新(化名)和其女友劉穎可训,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捶枢,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡握截,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烂叔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谨胞。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蒜鸡,靈堂內(nèi)的尸體忽然破棺而出胯努,到底是詐尸還是另有隱情,我是刑警寧澤逢防,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布叶沛,位于F島的核電站,受9級(jí)特大地震影響忘朝,放射性物質(zhì)發(fā)生泄漏灰署。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一局嘁、第九天 我趴在偏房一處隱蔽的房頂上張望溉箕。 院中可真熱鬧,春花似錦悦昵、人聲如沸约巷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)独郎。三九已至踩麦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氓癌,已是汗流浹背谓谦。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贪婉,地道東北人反粥。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像疲迂,于是被迫代替她去往敵國(guó)和親才顿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

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