runtime的常見(jiàn)使用

RunTime簡(jiǎn)介

因?yàn)镺bjc是一門(mén)動(dòng)態(tài)語(yǔ)言掘殴,所以它總是想辦法把一些決定工作從編譯連接推遲到運(yùn)行時(shí)舆乔。也就是說(shuō)只有編譯器是不夠的,還需要一個(gè)運(yùn)行時(shí)系統(tǒng) (runtime system) 來(lái)執(zhí)行編譯后的代碼。這就是 Objective-C Runtime 系統(tǒng)存在的意義茎杂,它是整個(gè)Objc運(yùn)行框架的一塊基石。

RunTime簡(jiǎn)稱(chēng)運(yùn)行時(shí)纫雁。OC就是運(yùn)行時(shí)機(jī)制煌往,其中最主要的是消息機(jī)制。對(duì)于C語(yǔ)言轧邪,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)刽脖。對(duì)于OC的函數(shù),屬于動(dòng)態(tài)調(diào)用過(guò)程忌愚,在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)曲管,只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱(chēng)找到對(duì)應(yīng)的函數(shù)來(lái)調(diào)用。

Runtime基本是用C和匯編寫(xiě)的硕糊,可見(jiàn)蘋(píng)果為了動(dòng)態(tài)系統(tǒng)的高效而作出的努力院水。你可以在這里下到蘋(píng)果維護(hù)的開(kāi)源代碼腊徙。蘋(píng)果和GNU各自維護(hù)一個(gè)開(kāi)源的runtime版本,這兩個(gè)版本之間都在努力的保持一致檬某。

RunTime中主要使用的函數(shù)定義在message.h和runtime.h這兩個(gè)文件中撬腾。 在message.h中主要包含了一些向?qū)ο蟀l(fā)送消息的函數(shù),這是OC對(duì)象方法調(diào)用的底層實(shí)現(xiàn)恢恼。

使用時(shí)民傻,需要導(dǎo)入文件,導(dǎo)入如:

#import <objc/message.h>
#import <objc/runtime.h>

函數(shù)的定義

  • 對(duì)對(duì)象進(jìn)行操作的方法一般以object_開(kāi)頭
  • 對(duì)類(lèi)進(jìn)行操作的方法一般以class_開(kāi)頭
  • 對(duì)類(lèi)或?qū)ο蟮姆椒?/code>進(jìn)行操作的方法一般以method_開(kāi)頭
  • 對(duì)成員變量進(jìn)行操作的方法一般以ivar_開(kāi)頭
  • 對(duì)屬性進(jìn)行操作的方法一般以property_開(kāi)頭開(kāi)頭
  • 對(duì)協(xié)議進(jìn)行操作的方法一般以protocol_開(kāi)頭

根據(jù)以上的函數(shù)的前綴 可以大致了解到層級(jí)關(guān)系厅瞎。

對(duì)于以objc_開(kāi)頭的方法饰潜,則是runtime最終的管家,可以獲取內(nèi)存中類(lèi)的加載信息,類(lèi)的列表和簸,關(guān)聯(lián)對(duì)象和關(guān)聯(lián)屬性等操作彭雾。

RunTime使用
一、runtime本質(zhì)锁保,消息發(fā)送

方法調(diào)用的本質(zhì)薯酝,就是讓對(duì)象發(fā)送消息。
objc_msgSend,只有對(duì)象才能發(fā)送消息爽柒,因此以objc開(kāi)頭.
使用消息機(jī)制前提吴菠,必須導(dǎo)入#import <objc/message.h>
代碼例子:

    // 創(chuàng)建person對(duì)象
    Person *p = [[Person alloc] init];
    
    // 調(diào)用對(duì)象方法
    [p eat];
    
    // 底層實(shí)現(xiàn):讓對(duì)象發(fā)送消息
    objc_msgSend(p, @selector(eat)); // Xcode5之后這里需要把 targets -> bulid Settings  搜索 msg 把objc_msgSend Calls YES 修改為 NO
    
    // 調(diào)用類(lèi)方法的方式:三種
    // 第一種通過(guò)類(lèi)名調(diào)用
    [Person eat];
    // 第二種通過(guò)類(lèi)對(duì)象調(diào)用
    [[Person class] eat];
    // 第三種調(diào)用方法
    [Person performSelector:@selector(eat)];
    
    // 用類(lèi)名調(diào)用類(lèi)方法,底層會(huì)自動(dòng)把類(lèi)名轉(zhuǎn)換成類(lèi)對(duì)象調(diào)用
    // 底層實(shí)現(xiàn) 讓類(lèi)對(duì)象發(fā)送消息
    objc_msgSend([Person class], @selector(eat));
    /**
     還有浩村,我是怎么知道上面的方法的本質(zhì)demo的呢做葵,
     我們可以通過(guò)clang 命令來(lái)查看代碼生成的CPP代碼。
     最終代碼,需要把當(dāng)前代碼重新編譯,用xcode編譯器,clang
     clang -rewrite-objc main.m 查看最終生成代碼
     **/

二心墅、runtime方法交換

交換方法實(shí)現(xiàn)的需求場(chǎng)景:
1酿矢、自己創(chuàng)建了一個(gè)功能性的方法,在項(xiàng)目中多次被引用怎燥,當(dāng)項(xiàng)目的需求發(fā)生改變時(shí)瘫筐,要使用另一種功能代替這個(gè)功能,要求是不改變舊的項(xiàng)目(也就是不改變?cè)瓉?lái)方法的實(shí)現(xiàn))铐姚。
2策肝、可以做一些異常處理,防止APP崩潰處理隐绵,(數(shù)組越界等等)

可以在類(lèi)的分類(lèi)中之众,再寫(xiě)一個(gè)新的方法(是符合新的需求的),然后交換兩個(gè)方法的實(shí)現(xiàn)。這樣依许,在不改變項(xiàng)目的代碼棺禾,而只是增加了新的代碼 的情況下,就完成了項(xiàng)目的改進(jìn)悍手。

交換兩個(gè)方法的實(shí)現(xiàn)一般寫(xiě)在類(lèi)的load方法里面帘睦,因?yàn)閘oad方法會(huì)在程序運(yùn)行前加載一次袍患,而initialize方法會(huì)在類(lèi)或者子類(lèi)在 第一次使用的時(shí)候調(diào)用,當(dāng)有分類(lèi)的時(shí)候會(huì)調(diào)用多次竣付。
下面demo是從這里看到的

@implementation NSMutableArray (Safe)
+ (void)load
{
    [NSClassFromString(@"__NSArrayM") swapMethod:@selector(objectAtIndex:)
                                   currentMethod:@selector(ls_objectAtIndex:)];
 
}
// 實(shí)例方法的交換
+ (void)swapMethod:(SEL)originMethod currentMethod:(SEL)currentMethod;
{
    Method firstMethod = class_getInstanceMethod(self, originMethod);
    Method secondMethod = class_getInstanceMethod(self, currentMethod);
    method_exchangeImplementations(firstMethod, secondMethod);
}

- (id)ls_objectAtIndex:(NSUInteger)index
{
    if (index >= self.count)
    {
        NSLog(@"數(shù)組越界诡延;;古胆;肆良;;逸绎;惹恃;;棺牧;巫糙;;颊乘;");
        return nil;
    }
    return [self ls_objectAtIndex:index];
}
@end

三参淹、獲取相關(guān)參數(shù)

1、獲取成員變量乏悄,包括屬性生成的成員變量

+ (NSArray *)fetchIvarList
{
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(self, &count);
    
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:2];
        const char *ivarName = ivar_getName(ivarList[i]);
        const char *ivarType = ivar_getTypeEncoding(ivarList[i]);
        dic[@"type"] = [NSString stringWithUTF8String:ivarType];
        dic[@"ivarName"] = [NSString stringWithUTF8String:ivarName];
        
        [mutableList addObject:dic];
    }
    free(ivarList);
    return [NSArray arrayWithArray:mutableList];
}

2浙值、獲取類(lèi)的屬性列表,包括私有和公有屬性檩小,也包括分類(lèi)中的屬性

+ (NSArray *)fetchPropertyList
{
    unsigned int count = 0;
    objc_property_t *propertyList = class_copyPropertyList(self, &count);
    
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        const char *propertyName = property_getAttributes(propertyList[i]);
        [mutableList addObject:[NSString stringWithUTF8String:propertyName]];
    }
    free(propertyList);
    return [NSArray arrayWithArray:mutableList];
}

3开呐、 獲取對(duì)象方法列表:包括getter, setter, 分類(lèi)中的方法等

+ (NSArray *)fetchInstanceMethodList
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(self, &count);
    
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return [NSArray arrayWithArray:mutableList];
}

4、獲取類(lèi)方法列表 包括分類(lèi)里面的

+ (NSArray *)fetchClassMethodList
{
    unsigned int count = 0;
    Method *methodList = class_copyMethodList(object_getClass(self), &count);
    
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++)
    {
        Method method = methodList[i];
        SEL methodName = method_getName(method);
        [mutableList addObject:NSStringFromSelector(methodName)];
    }
    free(methodList);
    return [NSArray arrayWithArray:mutableList];
}

5规求、獲取協(xié)議列表筐付,包括.h .m 和分類(lèi)里的

+ (NSArray *)fetchProtocolList
{
    unsigned int count = 0;
    __unsafe_unretained Protocol **protocolList = class_copyProtocolList(self, &count);
    
    NSMutableArray *mutableList = [NSMutableArray arrayWithCapacity:count];
    for (unsigned int i = 0; i < count; i++ )
    {
        Protocol *protocol = protocolList[i];
        const char *protocolName = protocol_getName(protocol);
        [mutableList addObject:[NSString stringWithUTF8String:protocolName]];
    }
    
    return [NSArray arrayWithArray:mutableList];
}
四、關(guān)聯(lián)對(duì)象

關(guān)聯(lián)對(duì)象不是為類(lèi)\對(duì)象添加屬性或者成員變量(因?yàn)樵谠O(shè)置關(guān)聯(lián)后也無(wú)法通過(guò)ivarList或者propertyList取得) 颓哮,而是為類(lèi)添加一個(gè)相關(guān)的對(duì)象家妆,通常用于存儲(chǔ)類(lèi)信息鸵荠,例如存儲(chǔ)類(lèi)的屬性列表數(shù)組冕茅,為將來(lái)字典轉(zhuǎn)模型的方便。
1蛹找、對(duì)象關(guān)聯(lián)屬性
列如姨伤,oc里面,類(lèi)沒(méi)有name 這個(gè)參數(shù)庸疾,我們可以給他添加一個(gè)name

// 定義關(guān)聯(lián)的key
static const char *key = "name";
@implementation NSObject (RunTime)

- (NSString *)name
{
    // 根據(jù)關(guān)聯(lián)的key乍楚,獲取關(guān)聯(lián)的值。
    return objc_getAssociatedObject(self, key);
}
- (void)setName:(NSString *)name
{
    // 第一個(gè)參數(shù):給哪個(gè)對(duì)象添加關(guān)聯(lián)
    // 第二個(gè)參數(shù):關(guān)聯(lián)的key届慈,通過(guò)這個(gè)key獲取
    // 第三個(gè)參數(shù):關(guān)聯(lián)的value
    // 第四個(gè)參數(shù):關(guān)聯(lián)的策略
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

// 調(diào)用
    // NSObject對(duì)象添加屬性
    NSObject * object = [[NSObject alloc] init];
    object.name = @"gameover";
    NSLog(@"object  name =====%@",object.name);
// 打印 如下 
//2018-06-28 14:52:54.302050+0800 Test_runTime[23578:9984095] object  name ===== gameover

2徒溪、對(duì)象關(guān)聯(lián)對(duì)象
動(dòng)態(tài)添加方法會(huì)用到這兩個(gè)api
objc_setAssociatedObject
第一個(gè)參數(shù) id object, 當(dāng)前對(duì)象
第二個(gè)參數(shù) const void *key, 關(guān)聯(lián)的key忿偷,是c字符串
第三個(gè)參數(shù) id value, 被關(guān)聯(lián)的對(duì)象的值
第四個(gè)參數(shù) objc_AssociationPolicy policy關(guān)聯(lián)引用的規(guī)則
objc_getAssociatedObject
第一個(gè)參數(shù) id object, 當(dāng)前對(duì)象
第二個(gè)參數(shù) const void *key, 關(guān)聯(lián)的key,是c字符串

- (void)viewDidLoad {
    //  對(duì)象添加關(guān)聯(lián)對(duì)象
    //  列如btn 對(duì)象添加多個(gè)參數(shù)臊泌,
    UIButton * btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 40)];
    btn.backgroundColor = [UIColor redColor];
    
    [self.view addSubview:btn];
    [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    // 傳遞多參數(shù)
    objc_setAssociatedObject(btn, "yt_text", @"你好", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_setAssociatedObject(btn, "yt_size", @"15", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

// 點(diǎn)擊按鈕觸發(fā)
- (void)btnClick:(UIButton*)btn
{
    NSString *yt_text = objc_getAssociatedObject(btn, "yt_text");
    NSString *yt_size = objc_getAssociatedObject(btn, "yt_size");
    NSLog(@"yt_text ==%@  yt_size ==%@",yt_text,yt_size);
}
// 打印 如下 
//2018-06-28 14:50:32.083111+0800 Test_runTime[23575:9981192] yt_text ==你好  yt_size ==15
五鲤桥、動(dòng)態(tài)添加方法

在開(kāi)發(fā)中:如果一個(gè)類(lèi)的方法非常多的時(shí)候,加載類(lèi)到內(nèi)存的時(shí)候也比較耗費(fèi)資源渠概,需要給每個(gè)方法生成映射表茶凳,可以使用動(dòng)態(tài)給某個(gè)類(lèi),添加方法解決

動(dòng)態(tài)添加方法會(huì)用到這個(gè)api
class_addMethod
第一個(gè)參數(shù):給哪個(gè)類(lèi)添加方法
第二個(gè)參數(shù):添加方法的方法編號(hào)
第三個(gè)參數(shù):添加方法的函數(shù)實(shí)現(xiàn)(函數(shù)地址)
第四個(gè)參數(shù):函數(shù)的類(lèi)型播揪,(返回值+參數(shù)類(lèi)型) v:void @:對(duì)象->self :表示SEL->_cmd

在使用[p performSelector:@selector(yt_sleep) withObject:nil]; 或者
的時(shí)候贮喧,由于 yt_sleep 這個(gè)方法在Person.m里面是沒(méi)有實(shí)現(xiàn)
所以,會(huì)崩潰猪狈。

所以只要在下面兩個(gè)方法里面分別動(dòng)態(tài)添加方法即可避免該問(wèn)題
在調(diào)用沒(méi)有實(shí)現(xiàn)的實(shí)例方法會(huì)觸發(fā)這個(gè)方法
+ (BOOL)resolveInstanceMethod:(SEL)sel;
在調(diào)用沒(méi)有實(shí)現(xiàn)的類(lèi)方法會(huì)觸發(fā)這個(gè)方法
+(BOOL)resolveClassMethod:(SEL)sel;

#import <Foundation/Foundation.h>
@interface Person : NSObject

+ (void)eat;
- (void)eat;
+ (void)yt_sleep;
@end

#import "Person.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation Person

- (void)eat
{
    NSLog(@"eat 方法調(diào)用");
}

+ (void)eat
{
    NSLog(@"eat 類(lèi)方法調(diào)用");
}

//+ (void)yt_sleep
//{
//    NSLog(@"sleep 類(lèi)方法調(diào)用");
//}

//當(dāng)類(lèi)調(diào)用一個(gè)沒(méi)有實(shí)現(xiàn)的類(lèi)方法就會(huì)到這里O渎佟!
+(BOOL)resolveClassMethod:(SEL)sel{
    NSLog(@"類(lèi)方法 %@",NSStringFromSelector(sel));
    if (sel == @selector(yt_sleep)) {
        /*
         第一個(gè)參數(shù):給哪個(gè)類(lèi)添加方法
         第二個(gè)參數(shù):添加方法的方法編號(hào)
         第三個(gè)參數(shù):添加方法的函數(shù)實(shí)現(xiàn)(函數(shù)地址)
         第四個(gè)參數(shù):函數(shù)的類(lèi)型雇庙,(返回值+參數(shù)類(lèi)型) v:void @:對(duì)象->self :表示SEL->_cmd
         */
        //class_addMethod(self, @selector(yt_sleep), (IMP)yt_sleep, "v@:"); // 這樣會(huì)崩潰
        class_addMethod(objc_getMetaClass("Person"), @selector(yt_sleep), (IMP)yt_sleep, "v@:");
    }
    return [super resolveClassMethod:sel];
}

//當(dāng)類(lèi)調(diào)用一個(gè)沒(méi)有實(shí)現(xiàn)的對(duì)象方法就會(huì)到這里1テ铡!
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"實(shí)例方法 %@",NSStringFromSelector(sel));
    if (sel == @selector(yt_sleep)) {
        // 動(dòng)態(tài)添加eat方法
        /*
         第一個(gè)參數(shù):給哪個(gè)類(lèi)添加方法
         第二個(gè)參數(shù):添加方法的方法編號(hào)
         第三個(gè)參數(shù):添加方法的函數(shù)實(shí)現(xiàn)(函數(shù)地址)
         第四個(gè)參數(shù):函數(shù)的類(lèi)型状共,(返回值+參數(shù)類(lèi)型) v:void @:對(duì)象->self :表示SEL->_cmd
         */
        class_addMethod(self, sel, (IMP)yt_sleep, "v@:");
    }
    return [super resolveInstanceMethod:sel];
}

// 默認(rèn)方法都有兩個(gè)隱式參數(shù)套耕,
void yt_sleep(id self,SEL sel)
{
    NSLog(@"%@ %@  睡覺(jué)了",self,NSStringFromSelector(sel));
}

@end


    //其他地方調(diào)用
    // 動(dòng)態(tài)添加實(shí)例方法
    [p performSelector:@selector(yt_sleep) withObject:nil];
    // 動(dòng)態(tài)添加類(lèi)方法
    [Person performSelector:@selector(yt_sleep) withObject:nil];
六、字典轉(zhuǎn)模型

MJExtension 里面就使用runTime來(lái)完成這些相應(yīng)的操作的
下面是我的偽代碼(沒(méi)有mj那么精細(xì))

#import <Foundation/Foundation.h>

@interface User : NSObject
@property (nonatomic ,strong) NSString * id;
@property (nonatomic ,strong) NSString * name;
@property (nonatomic ,strong) NSString * sex;
@property (nonatomic ,strong) NSString * age;
@property (nonatomic ,strong) NSString * height;
@property (nonatomic ,strong) NSString * weight;
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@end


#import "User.h"
#import <objc/runtime.h>
@implementation User
// Ivar:成員變量 以下劃線(xiàn)開(kāi)頭
// Property:屬性
+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    id objc = [[self alloc] init];
    
    // runtime:根據(jù)模型中屬性,去字典中取出對(duì)應(yīng)的value給模型屬性賦值
    // 1.獲取模型中所有成員變量 key
    // 獲取哪個(gè)類(lèi)的成員變量
    // count:成員變量個(gè)數(shù)
    unsigned int count = 0;
    // 獲取成員變量數(shù)組
    Ivar *ivarList = class_copyIvarList(self, &count);
    
    // 遍歷所有成員變量
    for (int i = 0; i < count; i++) {
        // 獲取成員變量
        Ivar ivar = ivarList[i];
        
        // 獲取成員變量名字
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        // 獲取成員變量類(lèi)型
        NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        // @\"User\" -> User
        ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
        ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
        // 獲取key
        NSString *key = [ivarName substringFromIndex:1];
        
        // 去字典中查找對(duì)應(yīng)value
        // key:user  value:NSDictionary
        
        id value = dict[key];
        
        // 二級(jí)轉(zhuǎn)換:判斷下value是否是字典,如果是,字典轉(zhuǎn)換層對(duì)應(yīng)的模型
        // 并且是自定義對(duì)象才需要轉(zhuǎn)換
        if ([value isKindOfClass:[NSDictionary class]] && ![ivarType hasPrefix:@"NS"]) {
            // 字典轉(zhuǎn)換成模型 userDict => User模型
            // 轉(zhuǎn)換成哪個(gè)模型
            
            // 獲取類(lèi)
            Class modelClass = NSClassFromString(ivarType);
            
            value = [modelClass modelWithDict:value];
        }
        
        // 給模型中屬性賦值
        if (value) {
            [objc setValue:value forKey:key];
        }
    }
    return objc;
}
@end
// 其他地方調(diào)用
    // 字典轉(zhuǎn)模型
    NSDictionary * dict = @{ @"id" : @"1235",
                            @"name" : @"帥哥",
                            @"sex" : @"男",
                            @"age" : @"18",
                            @"height" : @"180cm",
                            @"weight" : @"70kg",
                            @"good" : @"eat",
                            @"money" : @"10000",
                            @"sport" : @"basketball"};
    
    
    User * user = [User modelWithDict:dict];
    NSLog(@"id =%@  name =%@ sex =%@ age =%@ height =%@ weight =%@",user.id,user.name,user.sex,user.age,user.height,user.weight);

打印如下
2018-06-28 17:00:07.724910+0800 Test_runTime[23654:10029472] id =1235 name =帥哥 sex =男 age =18 height =180cm weight =70kg

QQ20180628-170248.png


以上是本人的淺見(jiàn)峡继,如有錯(cuò)誤冯袍,望各位多多指正??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碾牌,隨后出現(xiàn)的幾起案子康愤,更是在濱河造成了極大的恐慌,老刑警劉巖舶吗,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件征冷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡誓琼,警方通過(guò)查閱死者的電腦和手機(jī)检激,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腹侣,“玉大人叔收,你說(shuō)我怎么就攤上這事“亮ィ” “怎么了饺律?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)跺株。 經(jīng)常有香客問(wèn)我复濒,道長(zhǎng)脖卖,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任巧颈,我火速辦了婚禮胚嘲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洛二。我一直安慰自己馋劈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布晾嘶。 她就那樣靜靜地躺著妓雾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垒迂。 梳的紋絲不亂的頭發(fā)上械姻,一...
    開(kāi)封第一講書(shū)人閱讀 52,328評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音机断,去河邊找鬼楷拳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吏奸,可吹牛的內(nèi)容都是我干的欢揖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼奋蔚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼她混!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起泊碑,我...
    開(kāi)封第一講書(shū)人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坤按,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后馒过,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體臭脓,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年腹忽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了来累。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡留凭,死狀恐怖佃扼,靈堂內(nèi)的尸體忽然破棺而出偎巢,到底是詐尸還是另有隱情蔼夜,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布压昼,位于F島的核電站求冷,受9級(jí)特大地震影響瘤运,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜匠题,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一拯坟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧韭山,春花似錦郁季、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至盖淡,卻和暖如春年柠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背褪迟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工冗恨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人味赃。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓掀抹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親心俗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子渴丸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

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