iOS方法交換研究

1、Class/SEL/Method/IMP

Class+SEL=>Method=>IMP,...

2、class_

class_addMethod/class_replaceMethod/method_exchangeImplementations

class_addMethod//如果要添加的A方法已經(jīng)存在則返回NO
A->B,B->B
method_exchangeImplementations
A->B,B->A
class_replaceMethod
A->B,B->B

3、消息處理機(jī)制

objc_msgSend/NSInvocation+NSMethodSignature/perfermSelector

1辩稽、更低層c語(yǔ)言實(shí)現(xiàn)
id objc_msgSend(id self, SEL op, ...)

2厢蒜、oc的封裝高級(jí)層
NSMethodSignature=返回值類型+參數(shù)(列)類型
SEL=函數(shù)名字
NSInvocation=target+SEL+NSMethodSignature
getArgumentTypeAtIndex:第0個(gè)參數(shù)是target,第1個(gè)參數(shù)是SEL油额,其它的參數(shù)(列)從第2,3刻帚,4潦嘶,下標(biāo)開始。

3崇众、消息處理機(jī)制總結(jié):

那么 objc_msgSend 到底是怎么工作的呢掂僵?

在Objective-C中,消息直到運(yùn)行時(shí)才會(huì)綁定到方法的實(shí)現(xiàn)上顷歌。編譯器會(huì)把代碼中[target doSth]轉(zhuǎn)換成 objc_msgSend消息函數(shù)看峻,這個(gè)函數(shù)完成了動(dòng)態(tài)綁定的所有事情。它的運(yùn)行流程如下:

檢查selector是否需要忽略衙吩。(ps: Mac開發(fā)中開啟GC就會(huì)忽略retain,release方法互妓。)

檢查target是否為nil。如果為nil,直接cleanup冯勉,然后return澈蚌。(這就是我們可以向nil發(fā)送消息的原因。)

然后在target的Class中根據(jù)Selector去找IMP

尋找IMP的過程:

先從當(dāng)前class的cache方法列表(cache methodLists)里去找

找到了灼狰,跳到對(duì)應(yīng)函數(shù)實(shí)現(xiàn)

沒找到宛瞄,就從class的方法列表(methodLists)里找

還找不到,就到super class的方法列表里找交胚,直到找到基類(NSObject)為止

最后再找不到份汗,就會(huì)進(jìn)入動(dòng)態(tài)方法解析和消息轉(zhuǎn)發(fā)的機(jī)制。(這部分知識(shí)蝴簇,下次再細(xì)談)

0:對(duì)應(yīng)SEL(對(duì)應(yīng)參數(shù))找到否 respondsToSelector
1:動(dòng)態(tài)addmethod機(jī)會(huì) 實(shí)例方法調(diào)resolveInstanceMethod杯活, 類方法調(diào)resolveClassMethod
2:重定向target機(jī)會(huì) forwardingTargetForSelector
3:重定向NSInvocation機(jī)會(huì) methodSignatureForSelector/forwardInvocation
4:無法識(shí)別異常退出 doesNotRecognizeSelector

4、容易混淆的類型


NSObject

@protocol NSObject

OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0)
OBJC_ROOT_CLASS
OBJC_EXPORT
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}




Class
typedef struct objc_class *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;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;//變量
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;//方法名字+參數(shù)類型+imp函數(shù)指針
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//協(xié)議熬词?
#endif

} OBJC2_UNAVAILABLE;



SEL
typedef  struct objc_selector *SEL
SEL本質(zhì)是一個(gè)字符串,到底是結(jié)構(gòu)體還是字符串


Method
typedef struct objc_method *Method;
struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;
    char *method_types                                       OBJC2_UNAVAILABLE;
    IMP method_imp                                           OBJC2_UNAVAILABLE;
}       


IMP


id (*IMP)(id, SEL, ...)
typedef id (*IMP)(id,SEL,...) 要添加的方法


5旁钧、方法交換實(shí)踐



//RAC的方法交換。selector和block
// 因?yàn)閐ealloc方法不能用selector互拾,報(bào)錯(cuò)信息:ARC forbids use of 'dealloc' in a @selector
static const void *RACObjectCompoundDisposable = &RACObjectCompoundDisposable;

static NSMutableSet *swizzledClasses() {
    static dispatch_once_t onceToken;
    static NSMutableSet *swizzledClasses = nil;
    dispatch_once(&onceToken, ^{
        swizzledClasses = [[NSMutableSet alloc] init];
    });
    
    return swizzledClasses;
}

static void swizzleDeallocIfNeeded(Class classToSwizzle) {
    @synchronized (swizzledClasses()) {
        NSString *className = NSStringFromClass(classToSwizzle);
        if ([swizzledClasses() containsObject:className]) return;

        SEL deallocSelector = sel_registerName("dealloc");
        //__unsafe_unretained: 并不對(duì)其保持強(qiáng)引用歪今,這一點(diǎn)和__weak修飾符的變量一樣。當(dāng)這塊地址的內(nèi)存被系統(tǒng)回收時(shí)颜矿,它仍然指向這個(gè)地址寄猩。weak會(huì)自動(dòng)變?yōu)閚il。 再次訪問__unsafe_unretained釋放了內(nèi)存的地址骑疆,會(huì)產(chǎn)生奔潰田篇。
        __block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;

        id newDealloc = ^(__unsafe_unretained id self) {
            RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable);
            [compoundDisposable dispose];

            if (originalDealloc == NULL) {
                struct objc_super superInfo = {
                    .receiver = self,
                    .super_class = class_getSuperclass(classToSwizzle)
                };

                void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper;
                msgSend(&superInfo, deallocSelector);
            } else {
                originalDealloc(self, deallocSelector);
            }
        };
        
        IMP newDeallocIMP = imp_implementationWithBlock(newDealloc);
        //如果當(dāng)前類沒有實(shí)現(xiàn)dealloc,則dealloc直接被替換為新的dealloc的block指針封断;如果實(shí)現(xiàn)了,則保存dealloc的block指針舶担。
        if (! class_addMethod(classToSwizzle,
                            deallocSelector,
                            newDeallocIMP,
                            "v@:")) {
            // The class already contains a method implementation.
            Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector);
            
            // We need to store original implementation before setting new implementation
            // in case method is called at the time of setting.
            originalDealloc = (__typeof__(originalDealloc))method_getImplementation(deallocMethod);
            
            // We need to store original implementation again, in case it just changed.
            originalDealloc = (__typeof__(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
        }

        [swizzledClasses() addObject:className];
    }
}


//  yykit 不支持協(xié)議方法的交換
BOOL swizzleInstanceMethod(Class aClass, SEL originalSel, SEL newSel) {
    //    SEL
    //    typedef  struct objc_selector *SEL
    //    SEL本質(zhì)是一個(gè)字符串,到底是結(jié)構(gòu)體還是字符串
    // Method
    //    struct objc_method {
    //        SEL method_name                                          OBJC2_UNAVAILABLE;
    //        char *method_types                                       OBJC2_UNAVAILABLE;
    //        IMP method_imp                                           OBJC2_UNAVAILABLE;
    //    }
    Method originalMethod = class_getInstanceMethod(aClass, originalSel);
    Method newMethod = class_getInstanceMethod(aClass, newSel);
    if (!originalMethod || !newMethod) return NO;
    // 動(dòng)態(tài)添加方法
    //BOOL class_addMethod(Class cls, SEL name, IMP imp,  const char *types)
    class_addMethod(aClass,// 被添加的類
                    originalSel, // 方法名坡疼。如果存在則添加不了。如果不存在衣陶,可以添加柄瑰。
                    
                    //        id (*IMP)(id, SEL, ...)
                    //        typedef id (*IMP)(id,SEL,...) 要添加的方法
                    class_getMethodImplementation(aClass, originalSel),
                    
                    method_getTypeEncoding(originalMethod));// 添加方法的返回類型和參數(shù)類型
    class_addMethod(aClass,// 被添加的類
                    // 指定一個(gè)類的方法(成員方法/類方法)
                    newSel,
                    // 把一個(gè)類的方法(成員方法/類方法),轉(zhuǎn)化為c語(yǔ)言的函數(shù)指針剪况。
                    class_getMethodImplementation(aClass, newSel),
                    // 參數(shù):返回值類型教沾,參數(shù)列表
                    method_getTypeEncoding(newMethod));
    
    method_exchangeImplementations(class_getInstanceMethod(aClass, originalSel),
                                   class_getInstanceMethod(aClass, newSel));
    return YES;
}

//   支持協(xié)議方法的交換
BOOL rp_classMethodSwizzle(Class aClass, SEL originalSelector, SEL swizzleSelector, SEL nopSelector) {
    
    Method originalMethod = class_getInstanceMethod(aClass, originalSelector);
    Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSelector);
    
    BOOL didAddMethod = class_addMethod(aClass,
                                        originalSelector,
                                        method_getImplementation(swizzleMethod),
                                        method_getTypeEncoding(swizzleMethod));
    
    if (didAddMethod) {
        Method nopMehtod = class_getInstanceMethod(aClass, nopSelector);
        // 方法1--最妥
        class_replaceMethod(aClass,
                        swizzleSelector,
                        method_getImplementation(nopMehtod),
                        method_getTypeEncoding(nopMehtod));
        // 方法2--如果直接掉nopMethod會(huì)麻煩
        //method_exchangeImplementations(nopMehtod, swizzleMethod);
        
        // 方法3-- 不支持協(xié)議方法的交換
        //char *typeeconding=method_getTypeEncoding(originalMethod);
        //IMP imp1=method_getImplementation(originalMethod);
        //// 如果imp參數(shù)為nil則不能替換
        //class_replaceMethod(aClass, swizzleSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        // 交換method1和method2的
        // A->B,B->A
        method_exchangeImplementations(originalMethod, swizzleMethod);
        //這種不行。沒有交換译断,只是僅僅替換授翻。A->B,B->B
        //   class_replaceMethod(aClass, originalSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    }
    
    return YES;
}


 // 處理特點(diǎn):強(qiáng)制轉(zhuǎn)化對(duì)應(yīng)的函數(shù)指針。根據(jù)參數(shù)的個(gè)數(shù),強(qiáng)轉(zhuǎn)對(duì)應(yīng)參數(shù)個(gè)數(shù)類型的函數(shù)
 id objc_msgSend(id self, SEL op, ...)
 
 
 //  先把objc_msgSend函數(shù)指針強(qiáng)制轉(zhuǎn)化為void*類型堪唐,在強(qiáng)制轉(zhuǎn)化為“返回void類型(無返回參數(shù))巡语,3個(gè)參數(shù):id,SEL,int8_t”這個(gè)類型的函數(shù)的指針。再調(diào)用此函數(shù)淮菠。
 ((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
 
 //  先把objc_msgSend函數(shù)指針強(qiáng)制轉(zhuǎn)化為void*類型男公,在強(qiáng)制轉(zhuǎn)化為“返回SEL類型,2個(gè)參數(shù):id,SEL”這個(gè)類型的函數(shù)的指針合陵。再調(diào)用此函數(shù)枢赔。
 SEL value = ((SEL (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
 
 //  先把objc_msgSend函數(shù)指針強(qiáng)制轉(zhuǎn)化為void*類型,在強(qiáng)制轉(zhuǎn)化為“返回double類型拥知,2個(gè)參數(shù):id,SEL”這個(gè)類型的函數(shù)的指針踏拜。再調(diào)用次此數(shù)。
 double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
 
 
 // 先把objc_msgSend函數(shù)指針強(qiáng)制轉(zhuǎn)化為void*類型举庶,在強(qiáng)制轉(zhuǎn)化為“返回void類型(無返回參數(shù))执隧,3個(gè)參數(shù):id,SEL,double這個(gè)類型的函數(shù)的指針户侥。再調(diào)用次此數(shù)镀琉。
 ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
 
 
 Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
 value = v ? NSStringFromClass(v) : nil;
 void *pointer = ((void* (*)(id, SEL))(void *) objc_msgSend)((id)model, property->_getter);
 propertyDesc = [NSString stringWithFormat:@"%p",pointer];





/**
 1、
 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
 
 + (NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("");
 
 2蕊唐、
 NSInvocation和NSMethodSingature的target屋摔,sel都不匹配也能行。sel的名不一樣也行替梨。
 但是sel的參數(shù)個(gè)數(shù)不一致钓试,會(huì)閃退。
 如果NSMethodSignature返回nil副瀑,NSInvocation構(gòu)建會(huì)閃退弓熏。
 所以target,sel 最好是一致匹配的糠睡。
 為了保證NSMethodSignature不返回nil挽鞠,NSMethodSingature的target和NSInvocation的target要不一樣。
 
 3狈孔、
 target是0信认,sel是1呜舒,其它參數(shù)是2户誓,3,4....
 
 
 總結(jié):
 NSMethodSignature/NSInvocation  可以向任意的target發(fā)送sel消息脖隶,傳遞參數(shù)油挥,獲取返回值潦蝇。
 NSMethodSignature:定義:Sel名款熬,參數(shù),返回值
 
 */
+ (void)testNSInvocation{
    //SimpleNSInvocationClassA *a =[SimpleNSInvocationClassA new];
    //NSMethodSignature*signature= [a methodSignatureForSelector:@selector(method_b1:)];
    
    
    
    {
        SimpleNSInvocationClassB*b=[SimpleNSInvocationClassB new];
        NSMethodSignature*signature = [b methodSignatureForSelector:@selector(method_b1:)];
        NSInvocation *invocation=[NSInvocation  invocationWithMethodSignature:signature];
        invocation.target=b;
        invocation.selector=@selector(method_b1:);
        NSString*arg1=@"helloworld";
        [invocation setArgument:&arg1 atIndex:2];
        [invocation invoke];
    }
    
    
    
    {
        SimpleNSInvocationClassB*b=[SimpleNSInvocationClassB new];
        NSMethodSignature*signature = [b methodSignatureForSelector:@selector(method_b4:str2:str3:)];
        NSInvocation *invocation=[NSInvocation  invocationWithMethodSignature:signature];
        invocation.target=b;
        invocation.selector=@selector(method_b4:str2:str3:);
        NSString*arg1=@"helloworld";
        [invocation setArgument:&arg1 atIndex:2];
        BOOL result;
        [invocation getReturnValue:&result];
        
        
        /*
__unsafe_unretained: 并不對(duì)其保持強(qiáng)引用护蝶,這一點(diǎn)和__weak修飾符的變量一樣华烟。當(dāng)這塊地址的內(nèi)存被系統(tǒng)回收時(shí),它仍然指向這個(gè)地址持灰。weak會(huì)自動(dòng)變?yōu)閚il盔夜。
再次訪問__unsafe_unretained釋放了內(nèi)存的地址,會(huì)產(chǎn)生奔潰堤魁。
         NSNumber __unsafe_unretained *tempResult;
         [invocation getReturnValue:&tempResult];
         NSNumber *result = tempResult;
         return result;
         
         
         void *tempResult = NULL;
         [invocation getReturnValue:&tempResult];
         NSNumber *result = (__bridge NSNumber *)tempResult;
         return result;
         */
        [invocation invoke];
    }
    
    
    
}




+ (void)testNSINovcationReWrite {

    SimpleNSInvocationClassC*a=[SimpleNSInvocationClassC new];
    a.nocrash=[NoSelDoObj new];
    [a method_a];
    
    {
        TestMethod*tmp= [[self class]new];
        // 因?yàn)镾impleNSInvocationClassC沒有method_b方法喂链,所以NSMethodSignature用自己類method_b方法來構(gòu)建,簡(jiǎn)單妥泉。如果用signatureWithObjCTypes椭微,則比較麻煩。
        NSMethodSignature*sig=[tmp methodSignatureForSelector:@selector(method_b)];
        NSInvocation*invocation=[NSInvocation invocationWithMethodSignature:sig];
        [invocation setTarget:a];
        [invocation setSelector:@selector(method_b)];
        [invocation invoke];
    }
    
    
    {
        
        [a performSelector:@selector(method_b)];
    }
    
    
    {
        ((void (*)(id, SEL)) (void *)objc_msgSend)((id)a, @selector(method_b) );
    }
}


-(void)method_b{
    
    
}



@interface NoSelDoObj : NSObject

@end
@interface SimpleNSInvocationClassC : NSObject
@property(nonatomic,strong)NoSelDoObj*nocrash;


-(void)method_a;
@end


/**
 執(zhí)行順序:
 1盲链、如果有對(duì)應(yīng)的SEL蝇率,則直接執(zhí)行SEL方法
 2、如果不存在對(duì)應(yīng)的SEL則:
 resolveInstanceMethod/resolveClassMethod->返回YES刽沾,并動(dòng)態(tài)添加方法本慕,重新發(fā)送消息至動(dòng)態(tài)添加的方法。返回NO侧漓,或者未動(dòng)態(tài)添加方法锅尘,跳轉(zhuǎn)到forwardingTargetForSelector
 forwardingTargetForSelector->由哪個(gè)target來對(duì)應(yīng),如果此target有對(duì)應(yīng)的sel布蔗,則立即執(zhí)行藤违,如果此target沒有對(duì)應(yīng)的sel,則crash纵揍。如果返回target為nil顿乒,則繼續(xù)判斷。
 methodSignatureForSelector->由哪個(gè)NSMethodSignature(sel泽谨,返回值類型璧榄,參數(shù)類型)來對(duì)應(yīng),如果對(duì)應(yīng)NSMethodSignature為nil隔盛,則跳轉(zhuǎn)到最后一步doesNotRecognizeSelector犹菱,到這里發(fā)生crash
 forwardInvocation->重定向到此執(zhí)行invoke
 doesNotRecognizeSelector->如果以上都無法對(duì)應(yīng)拾稳,跳轉(zhuǎn)到這里crash
 */


@implementation SimpleNSInvocationClassC
- (void)method_a{
    NSLog(@"a");
    
}

- (IMP)methodForSelector:(SEL)aSelector {
    
    
    return [super methodForSelector:aSelector];
}

+ (IMP)instanceMethodForSelector:(SEL)aSelector{
    
    return [super instanceMethodForSelector:aSelector];
}

/**
 unrecognized selector sent to instance 0x60000000ce90
 找不到sel吮炕,會(huì)閃退
 */
- (void)doesNotRecognizeSelector:(SEL)aSelector{
    
    return [super doesNotRecognizeSelector:aSelector];
}

/**
 2: 重定向到其它消息接受者來執(zhí)行。
 返回其它消息SEL接受者访得。檢查是否有合適的target龙亲,如果不自定義陕凹,默認(rèn)返回nil
 */
- (id)forwardingTargetForSelector:(SEL)aSelector{
    id r= [super forwardingTargetForSelector:aSelector];
    //    if (!r&&sel_isEqual(aSelector, @selector(method_b))) {
    //        return _nocrash;
    //    }
    //    if (!r) {
    //        return _nocrash;
    //    }
    //
    
    return r;
}


/**
 3:  NSInvocation
 重定向到其它消息接受者、并對(duì)應(yīng)SEL方法
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    
    //An array of characters containing the type encodings for the method arguments.
    //NSMethodSignature只包括參數(shù)鳄炉。返回類型杜耙,參數(shù)(列)類型.通過Class和SEL可以獲取參數(shù)
    //NSMethodSignature*sig=  [self.nocrash methodSignatureForSelector:aSelector];
    //NSMethodSignature*sig=[super methodSignatureForSelector:aSelector];
    NSMethodSignature*sig=  [self.nocrash methodSignatureForSelector:@selector(method_c)];
    return sig;
}


/**
 methodSignatureForSelector -> forwardInvocation
 */
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSInvocation *invocation=anInvocation;
      //NSInvocation *invocation=[NSInvocation invocationWithMethodSignature:anInvocation.methodSignature];
    // 消息接受者。
    invocation.target=_nocrash;
    // SEL函數(shù)名拂盯。默認(rèn)是找不到的消息SEL佑女,可以改
    //invocation.selector=anInvocation.selector;
    invocation.selector=@selector(method_c);
    [invocation invoke];
    //   [super forwardInvocation:invocation];
    //   [super forwardInvocation:anInvocation];
}

+ (BOOL)resolveClassMethod:(SEL)sel {
    BOOL r= [super resolveClassMethod:sel];
    return r;
}

/**
 1: 執(zhí)行動(dòng)態(tài)添加方法的機(jī)會(huì)class_addMethod
 */
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    BOOL r= [super resolveInstanceMethod:sel];
    // 返回YES,并動(dòng)態(tài)添加方法谈竿,重新發(fā)送消息至動(dòng)態(tài)添加的方法团驱。
    //    if (sel==@selector(method_b)) {
    //        //Class+SEL->IMP, Class+SEL->Method->TypeEncoding
    //        class_addMethod([self class], sel, class_getMethodImplementation([TestMethod class], sel), method_getTypeEncoding(class_getInstanceMethod([TestMethod class], sel)));
    //        return YES;
    //    }
    // 返回NO空凸,或者未動(dòng)態(tài)添加方法嚎花,跳轉(zhuǎn)到forwardingTargetForSelector
    return r;
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    BOOL r=[super respondsToSelector:aSelector];
    return r;
}
@end

@implementation NoSelDoObj

-(void)method_b{
    MyLog(@"");
}
-(void)method_c {
    MyLog(@"");
}
@end




- (id)performSelectorWithArgs:(SEL)sel, ...{

NSMethodSignature * sig = [self methodSignatureForSelector:sel];
if (!sig) {
    [self doesNotRecognizeSelector:sel];
    return ((void *)0);
}
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:sig];
if (!inv) {
    [self doesNotRecognizeSelector:sel];
    return ((void *)0);
}

[inv setTarget:self];

[inv setSelector:sel];

va_list args;

__builtin_va_start(args, sel);

[NSObject setInv:inv withSig:sig andArgs:args];

__builtin_va_end(args);;

[inv invoke];

return [NSObject getReturnFromInv:inv withSig:sig];


}





最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市呀洲,隨后出現(xiàn)的幾起案子紊选,更是在濱河造成了極大的恐慌,老刑警劉巖道逗,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兵罢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡憔辫,警方通過查閱死者的電腦和手機(jī)趣些,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贰您,“玉大人坏平,你說我怎么就攤上這事〗跻啵” “怎么了舶替?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)杠园。 經(jīng)常有香客問我顾瞪,道長(zhǎng),這世上最難降的妖魔是什么抛蚁? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任陈醒,我火速辦了婚禮,結(jié)果婚禮上瞧甩,老公的妹妹穿的比我還像新娘钉跷。我一直安慰自己,他們只是感情好肚逸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布爷辙。 她就那樣靜靜地躺著彬坏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪膝晾。 梳的紋絲不亂的頭發(fā)上栓始,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音血当,去河邊找鬼幻赚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臊旭,可吹牛的內(nèi)容都是我干的坯屿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼巍扛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼领跛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撤奸,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吠昭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后胧瓜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矢棚,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年府喳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒲肋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡钝满,死狀恐怖兜粘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弯蚜,我是刑警寧澤孔轴,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站碎捺,受9級(jí)特大地震影響路鹰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜收厨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一晋柱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诵叁,春花似錦雁竞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至势腮,卻和暖如春联贩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捎拯。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工泪幌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人署照。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓祸泪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親建芙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子没隘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,690評(píng)論 0 9
  • 我們常常會(huì)聽說 Objective-C 是一門動(dòng)態(tài)語(yǔ)言禁荸,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢右蒲?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,182評(píng)論 0 7
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 749評(píng)論 0 1
  • 繼上Runtime梳理(四) 通過前面的學(xué)習(xí),我們了解到Objective-C的動(dòng)態(tài)特性:Objective-C不...
    小名一峰閱讀 744評(píng)論 0 3
  • 大學(xué)的圖書館也分淡季和旺季,平時(shí)上課期間就是淡季映砖,圖書館鮮有人來间坐,但是到了期末就是旺季,圖書館隨時(shí)會(huì)發(fā)生占座風(fēng)波邑退,...
    了望臺(tái)閱讀 286評(píng)論 0 1