動(dòng)態(tài)方法解析 & 消息轉(zhuǎn)發(fā)

消息轉(zhuǎn)發(fā)

由上文 Class 內(nèi)部結(jié)構(gòu) 可知:
objc_msgSend 到查找方法實(shí)現(xiàn) lookUpImpOrNil 的時(shí)候會(huì)先查找 當(dāng)前類 然后 父類(包括緩存列表)一層一層向上查找, 查找不到的時(shí)候就會(huì)進(jìn)入動(dòng)態(tài)方法解析, 那么動(dòng)態(tài)方法解析是怎么實(shí)現(xiàn)的?
且看源碼:

動(dòng)態(tài)方法解析 & 消息轉(zhuǎn)發(fā).png

1. 動(dòng)態(tài)方法解析

_class_resolveMethod(cls, sel, inst) :

void _class_resolveMethod(Class cls, SEL sel, id inst {
    // 1. 不是元類, 則為實(shí)例方法調(diào)用
    if (! cls->isMetaClass()) {
        // try [cls resolveInstanceMethod:sel]
        _class_resolveInstanceMethod(cls, sel, inst);
    } 
    else {
        // 2. 類方法動(dòng)態(tài)解析
        // try [nonMetaClass resolveClassMethod:sel]
        // and [cls resolveInstanceMethod:sel]
        _class_resolveClassMethod(cls, sel, inst);
        if (!lookUpImpOrNil(cls, sel, inst, 
                       NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) {
            // 3. 當(dāng)步驟 2 沒有處理(即 `+resolveClassMethod`返回值為 NO)時(shí), 
            // 才會(huì)走到步驟 3.
            _class_resolveInstanceMethod(cls, sel, inst);
        }
    }
}
實(shí)例方法動(dòng)態(tài)解析(類對(duì)象)(步驟 1)

調(diào)用沒有實(shí)現(xiàn)的實(shí)例方法時(shí), 會(huì)在類對(duì)象中查找動(dòng)態(tài)方法解析實(shí)現(xiàn), 即 :
_class_resolveInstanceMethod(cls, sel, inst) :

static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst) {
    // 檢查元類是否實(shí)現(xiàn) + resolveInstanceMethod 方法, 沒有則直接返回.
    if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, 
                    NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) {
        // Resolver not implemented.
        return;
    }

    // 發(fā)送 + resolveInstanceMethod 消息給當(dāng)前類(類對(duì)象)
    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);

    // 如果沒有處理(NSObject 默認(rèn)實(shí)現(xiàn)返回 NO), 則 imp 為空.
    // Cache the result (good or bad) so the resolver doesn't fire 
    // next time.
    // +resolveInstanceMethod adds to self a.k.a. cls
    IMP imp = lookUpImpOrNil(cls, sel, inst, 
                        NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
    // 打印 log
    ...
    }
}
類方法動(dòng)態(tài)解析(步驟 2)

元類中查找動(dòng)態(tài)方法解析實(shí)現(xiàn).

static void _class_resolveClassMethod(Class cls, SEL sel, id inst) {
    // 斷言 cls 為元類.
    assert(cls->isMetaClass());

    // 檢查 cls 是否有實(shí)現(xiàn) resolveClassMethod 方法, 沒有則直接返回.
    if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst, 
                       NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) {
        // Resolver not implemented.
        return;
    }

    // 給 cls 類對(duì)象發(fā)送 + resolveClassMethod 消息
    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(_class_getNonMetaClass(cls, inst), 
                        SEL_resolveClassMethod, sel);

    // 緩存方法的 imp,因?yàn)樵谏厦嬉徊揭呀?jīng)實(shí)現(xiàn)了方法動(dòng)態(tài)解析, 
    // 這里再作查詢(包含緩存)操作.
    // Cache the result (good or bad) so the resolver doesn't fire 
    // next time.
    // +resolveClassMethod adds to self->ISA() a.k.a. cls
    IMP imp = lookUpImpOrNil(cls, sel, inst, 
                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/);

    // 打印 log
    ...
    }
}
3. 實(shí)例方法動(dòng)態(tài)解析(元類對(duì)象)(步驟 3) - 重點(diǎn)難理解

注 : 雖然同步驟 1 的方法相同, 但是當(dāng)前類cls不一樣, 步驟 1 的當(dāng)前類 cls類對(duì)象, 而步驟 3 的當(dāng)前類 cls元類對(duì)象, 相當(dāng)于在元類中找 +方法(至 NSObject 根類找 -方法) !

static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst) {
    // 檢查元類是否實(shí)現(xiàn) + resolveInstanceMethod 方法, 沒有則直接返回.
    if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls, 
                    NO/*initialize*/, YES/*cache*/, NO/*resolver*/)) {
        // Resolver not implemented.
        return;
    }

    /* 發(fā)送 + resolveInstanceMethod 消息給當(dāng)前類(元類!!!)
       元類中找 '+ 方法' 操作, 僅在查找 NSObject 元類 '+ 方法'
       (查找父類即 NSObject 類對(duì)象的 '+ 方法', 即在 NSObject 元類里的 '- 方法')
       時(shí)才能找到(NSObject 默認(rèn)實(shí)現(xiàn)返回 NO, 需要重寫).
    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
    bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);

    // 如果沒有處理(NSObject 默認(rèn)實(shí)現(xiàn)返回 NO), 則 imp 為空.
    // Cache the result (good or bad) so the resolver doesn't fire 
    // next time.
    // +resolveInstanceMethod adds to self a.k.a. cls
    IMP imp = lookUpImpOrNil(cls, sel, inst, 
                        NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
    // 打印 log
    ...
    }
}

2. 消息轉(zhuǎn)發(fā)

在以上動(dòng)態(tài)方法解析失敗后, Xcode 便會(huì)告訴你找不到方法:

 Terminating app due to uncaught exception 'NSInvalidArgumentException', \
 reason: '+[WXPerson wx_classMethod]: unrecognized selector sent to \
 class 0x100002720'
*** First throw call stack:
(
    0   CoreFoundation    0x00007fff3d77ecf9 __exceptionPreprocess + 256
    1   libobjc.A.dylib   0x0000000100357a8f objc_exception_throw + 47
    2   CoreFoundation    0x00007fff3d7f8a56 __CFExceptionProem + 0
    3   CoreFoundation    0x00007fff3d7210ef ___forwarding___ + 1485
    4   CoreFoundation    0x00007fff3d720a98 _CF_forwarding_prep_0 + 120
    5   LGTest            0x0000000100001369 main + 57
    6   libdyld.dylib     0x00007fff69b403d5 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

發(fā)現(xiàn)調(diào)用棧中的方法都找不到, 蘋果隱藏了消息轉(zhuǎn)發(fā)的實(shí)現(xiàn)?
是的, 蘋果爸爸覺得這個(gè)消息轉(zhuǎn)發(fā)的實(shí)現(xiàn)非常??,于是對(duì)該處實(shí)現(xiàn)閉源了.
對(duì)此, 先根據(jù)已知調(diào)用方法進(jìn)行跟蹤查找, 即在方法動(dòng)態(tài)解析失敗后, 直接調(diào)用 _objc_msgForward_impcache 方法獲取 imp.
那么接下來就查找該方法, 結(jié)果發(fā)現(xiàn)該方法是由匯編實(shí)現(xiàn):

    STATIC_ENTRY __objc_msgForward_impcache

    // No stret specialization.
    b   __objc_msgForward

    END_ENTRY __objc_msgForward_impcache

    
    ENTRY __objc_msgForward

    adrp    x17, __objc_forward_handler@PAGE
    ldr p17, [x17, __objc_forward_handler@PAGEOFF]
    TailCallFunctionPointer x17
    
    END_ENTRY __objc_msgForward

從中可以看到跳轉(zhuǎn)到 __objcForward 后調(diào)用了 __objc_forward_handler :

// Default forward handler halts the process.
__attribute__((noreturn)) void 
objc_defaultForwardHandler(id self, SEL sel)
{
    _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
                "(no message forward handler is installed)", 
                class_isMetaClass(object_getClass(self)) ? '+' : '-', 
                object_getClassName(self), sel_getName(sel), self);
}
void *_objc_forward_handler = (void*)objc_defaultForwardHandler;

終于知道這報(bào)錯(cuò)出處了...
然后就沒有然后了...
但是! 從報(bào)錯(cuò)的調(diào)用棧中我們?nèi)匀豢梢钥吹较⑥D(zhuǎn)發(fā)調(diào)用了 CoreFoundation 框架, 于是迫不及待的下載 CoreFoundation 源碼進(jìn)行分析:
CoreFoundation 下載鏈接.
經(jīng)過一系列查找仍然找不到想要的方法...
既然我們知道轉(zhuǎn)發(fā)是在 CoreFoundation 中, 那么我們從匯編的角度來看下 CoreFoundation 對(duì)消息轉(zhuǎn)發(fā)到底隱藏了什么:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework
用 Hopper 打開 CoreFoundation 可執(zhí)行文件, 對(duì)其進(jìn)行分析, 由于是在 libobjc 調(diào)用了 objc_defaultForwardHandler, 所以在 CoreFoundation 中直接查找 ForwardHandler :

ForwardHandler.png

objc_setForwardHandler.png

可以看到該 CODE XREF=___CFInitialize+168, 那么直接進(jìn)入 ___CFInitialize 中查找 objc_setForwardHandler :

image.png

可以看到該函數(shù)注冊(cè)了兩個(gè)回調(diào):
___forwarding_prep_0______forwarding_prep_1___
搜索 ___forwarding_prep_ 關(guān)鍵字發(fā)現(xiàn)公有三個(gè)相似項(xiàng):
___forwarding_prep_.png

  • ___forwarding_prep_0___

    ___forwarding_prep_0___.png

  • ___forwarding_prep_1___

    ___forwarding_prep_1___.png

  • ___forwarding_prep_b___

    ___forwarding_prep_b___.png

  • ____forwarding___

int ____forwarding___(int arg0, int arg1) {
    rsi = arg1;
    var_30 = *___stack_chk_guard;
    r13 = arg0;
    rcx = COND_BYTE_SET(NE);
    if (rsi != 0x0) {
            r12 = _objc_msgSend_stret;
    }
    else {
            r12 = _objc_msgSend;
    }
    rbx = *(r13 + rcx * 0x8);
    var_40 = *(r13 + rcx * 0x8 + 0x8);
    r15 = rcx * 0x8;
    if (rbx >= 0x0) goto loc_12c9ba;

loc_12c989:
    rcx = *_objc_debug_taggedpointer_obfuscator;
    rcx = rcx ^ rbx;
    rax = rcx >> 0x3c & 0x7;
    if (rax == 0x7) {
            rax = (rcx >> 0x34 & 0xff) + 0x8;
    }
    if (rax == 0x0) goto loc_12cd4d;

loc_12c9ba:
    var_48 = r15;
    r15 = rsi;
    var_38 = r12;
    r12 = object_getClass(rbx);
    var_50 = class_getName(r12);
    r14 = @selector(forwardingTargetForSelector:);
    if (class_respondsToSelector(r12, r14) == 0x0) goto loc_12ca57;

loc_12c9f2:
    rax = _objc_msgSend(rbx, r14);
    if ((rax == 0x0) || (rax == rbx)) goto loc_12ca57;

loc_12ca0c:
    r12 = var_38;
    r15 = var_48;
    if (rax >= 0x0) goto loc_12ca4a;

loc_12ca19:
    rdx = *_objc_debug_taggedpointer_obfuscator;
    rdx = rdx ^ rax;
    rcx = rdx >> 0x3c & 0x7;
    if (rcx == 0x7) {
            rcx = (rdx >> 0x34 & 0xff) + 0x8;
    }
    if (rcx == 0x0) goto loc_12cd4a;

loc_12ca4a:
    *(0x0 + r15) = rax;
    r13 = 0x0;
    goto loc_12cd7d;

loc_12cd7d:
    if (*___stack_chk_guard == var_30) {
            rax = r13;
    }
    else {
            rax = __stack_chk_fail();
    }
    return rax;

loc_12cd4a:
    rbx = rax;
    goto loc_12cd4d;

loc_12cd4d:
    r14 = _getAtomTarget(rbx);
    *(r13 + r15) = r14;
    ___invoking___(r12, r13, r13, 0x400, 0x0);
    if (*r13 == r14) {
            *r13 = rbx;
    }
    goto loc_12cd7d;

loc_12ca57:
    var_38 = rbx;
    if (strncmp(var_50, "_NSZombie_", 0xa) == 0x0) goto loc_12cdbc;

loc_12ca78:
    rbx = @selector(methodSignatureForSelector:);
    var_48 = r13;
    if (class_respondsToSelector(r12, rbx) == 0x0) goto loc_12ce0d;

loc_12ca96:
    r12 = var_38;
    r14 = _objc_msgSend(r12, rbx);
    if (r14 == 0x0) goto loc_12ce6d;

loc_12cab6:
    rbx = [r14 _frameDescriptor];
    if (((*(int16_t *)(*rbx + 0x22) & 0xffff) >> 0x6 & 0x1) != r15) {
            rax = sel_getName(var_40);
            rsi = " not";
            r8 = "";
            rcx = r8;
            if ((*(int16_t *)(*rbx + 0x22) & 0xffff & 0x40) == 0x0) {
                    rcx = rsi;
            }
            rdx = rax;
            if (r15 == 0x0) {
                    r8 = rsi;
            }
            _CFLog(0x4, @"*** NSForwarding: warning: method signature and 
                  compiler disagree on struct-return-edness of '%s'.  
                  Signature thinks it does%s return a struct, 
                  and compiler thinks it does%s.", 
                                        rdx, rcx, r8, r9, stack[2037]);
    }
    var_50 = rbx;
    if (class_respondsToSelector(object_getClass(r12), 
         @selector(_forwardStackInvocation:)) != 0x0) {
            if (*____forwarding___.onceToken != 0xffffffffffffffff) {
                    dispatch_once(____forwarding___.onceToken, ^ { 
              /* block implemented at ______forwarding____block_invoke */ 
                    });
            }
            r13 = [NSInvocation requiredStackSizeForSignature:r14];
            rdx = *____forwarding___.invClassSize;
            r12 = rsp - (rdx + 0xf & 0xfffffffffffffff0);
            memset(r12, 0x0, rdx);
            objc_constructInstance(*____forwarding___.invClass, r12);
            var_40 = r13;
            [r12 _initWithMethodSignature:r14 
                                    frame:var_48 
                                   buffer:r12 - (r13 + 0xf & 0xfffffffffffffff0) 
                                      size:r13];
            [var_38 _forwardStackInvocation:r12];
            r15 = 0x1;
    }
    else {
            rbx = @selector(forwardInvocation:);
            if (class_respondsToSelector(object_getClass(r12), rbx) != 0x0) {
                    rdi = r12;
                    r12 = [NSInvocation _invocationWithMethodSignature:r14 
                                                                 frame:var_48];
                    _objc_msgSend(rdi, rbx);
            }
            else {
                    r12 = 0x0;
                    _CFLog(0x4, @"*** NSForwarding: warning: 
                            object %p of class '%s' does not implement 
                            forwardInvocation: -- dropping message",
                            0x0, object_getClassName(0x0), r8, r9, stack[2037]);
            }
            var_40 = 0x0;
            r15 = 0x0;
    }
    rax = var_50;
    if (r12->_retainedArgs != 0x0) {
            rax = *rax;
            if (*(int8_t *)(rax + 0x22) < 0x0) {
                    rdx = *(int32_t *)(rax + 0x1c);
                    rsi = *(int8_t *)(rax + 0x20) & 0xff;
                    memmove(*(rsi + var_48 + rdx), 
                             *(rsi + rdx + r12->_frame), 
                                *(int32_t *)(*rax + 0x10));
            }
    }
    rbx = [r14 methodReturnType];
    rax = *(int8_t *)rbx;
    if ((rax != 0x76) && (((rax != 0x56) || 
        (*(int8_t *)(rbx + 0x1) != 0x76)))) {
            r13 = r12->_retdata;
            if (r15 != 0x0) {
                    r13 = [[NSData dataWithBytes:r13 length:var_40] bytes];
                    [r12 release];
                    rax = *(int8_t *)rbx;
            }
            if (rax == 0x44) {
                    asm{ fld        tword [r13] };
            }
    }
    else {
            r13 = ____forwarding___.placeholder;
            if (r15 != 0x0) {
                    [r12 release];
            }
    }
    goto loc_12cd7d;

loc_12ce6d:
    r15 = sel_getName(var_40);
    r8 = sel_getUid(r15);
    if (r8 != var_40) {
            _CFLog(0x4, @"*** NSForwarding: warning: selector (%p) for message '%s' 
                   does not match selector known to Objective C runtime 
                   (%p)-- abort", var_40, r15, r8, r9, stack[2037]);
    }
    rbx = @selector(doesNotRecognizeSelector:);
    if (class_respondsToSelector(object_getClass(var_38), rbx) != 0x0) {
            rax = _objc_msgSend(var_38, rbx);
            asm{ ud2 };
    }
    else {
            rax = _CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' 
                         does not implement doesNotRecognizeSelector: 
                         -- abort", var_38, object_getClassName(var_38), 
                         r8, r9, stack[2037]);
            asm{ ud2 };
    }
    return rax;

loc_12ce0d:
    rbx = class_getSuperclass(r12);
    r14 = object_getClassName(var_38);
    if (rbx == 0x0) {
            _CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' 
                   does not implement methodSignatureForSelector: 
                   -- did you forget to declare the superclass of '%s'?",
                   var_38, r14, object_getClassName(var_38), r9, stack[2037]);
    }
    else {
            _CFLog(0x4, @"*** NSForwarding: warning: object %p of class '%s' 
                   does not implement methodSignatureForSelector: 
                   -- trouble ahead", var_38, r14, r8, r9, stack[2037]);
    }
    goto loc_12ce6d;

loc_12cdbc:
    if (*(int8_t *)___CFOASafe != 0x0) {
            ___CFRecordAllocationEvent();
    }
    rax = _CFLog(0x3, @"*** -[%s %s]: message sent to deallocated instance %p",
                 var_50 + 0xa, sel_getName(var_40), var_38, r9, stack[2037]);
    asm{ ud2 };
    return rax;
}

Forwarding 內(nèi)邏輯參考: forwardingforwarding
以下引用自 00Objective-C 消息發(fā)送與轉(zhuǎn)發(fā)機(jī)制原理(二):
1、先調(diào)用 forwardingTargetForSelector方法獲取新的 target 作為 receiver 重新執(zhí)行 selector,如果返回的內(nèi)容不合法(為 nil或者跟舊 receiver 一樣)魄眉,那就進(jìn)入第二步。
2修赞、調(diào)用 methodSignatureForSelector
獲取方法簽名后,判斷返回類型信息是否正確桑阶,再調(diào)用 forwardInvocation
執(zhí)行 NSInvocation對(duì)象柏副,并將結(jié)果返回。如果對(duì)象沒實(shí)現(xiàn)methodSignatureForSelector
方法蚣录,進(jìn)入第三步割择。
3、調(diào)用 doesNotRecognizeSelector方法萎河。

image.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荔泳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子虐杯,更是在濱河造成了極大的恐慌玛歌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擎椰,死亡現(xiàn)場(chǎng)離奇詭異支子,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)达舒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門值朋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人巩搏,你說我怎么就攤上這事昨登。” “怎么了贯底?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵丰辣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我禽捆,道長(zhǎng)糯俗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任睦擂,我火速辦了婚禮得湘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘顿仇。我一直安慰自己淘正,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布臼闻。 她就那樣靜靜地躺著鸿吆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪述呐。 梳的紋絲不亂的頭發(fā)上惩淳,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼思犁。 笑死代虾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的激蹲。 我是一名探鬼主播棉磨,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼学辱!你這毒婦竟也來了乘瓤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤策泣,失蹤者是張志新(化名)和其女友劉穎衙傀,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萨咕,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡统抬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了任洞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓄喇。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖交掏,靈堂內(nèi)的尸體忽然破棺而出妆偏,到底是詐尸還是另有隱情,我是刑警寧澤盅弛,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布钱骂,位于F島的核電站,受9級(jí)特大地震影響挪鹏,放射性物質(zhì)發(fā)生泄漏见秽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一讨盒、第九天 我趴在偏房一處隱蔽的房頂上張望解取。 院中可真熱鬧,春花似錦返顺、人聲如沸禀苦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽振乏。三九已至,卻和暖如春秉扑,著一層夾襖步出監(jiān)牢的瞬間慧邮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留误澳,地道東北人耻矮。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像脓匿,于是被迫代替她去往敵國(guó)和親淘钟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宦赠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359