用运行时命令实现不引入头文件

2018年9月21日
一.前期准备
1.如需要项目支持objc_msgSend

工程如下修改:
image.png

2.常见几种类型 函数原型
a.无返回值  无参数
void * (*action)(id, SEL) = (void *(*)(id, SEL)) objc_msgSend;

b.无返回值  带一个参数(多个参数类推即可)
 void * (*action)(id, SEL,NSString*) = (void *(*)(id, SEL,NSString*)) objc_msgSend;
 void * (*action)(id, SEL,id) = (void *(*)(id, SEL,id)) objc_msgSend;

c.返回值  带一个参数
NSString * (*action)(id, SEL,NSString*) = (NSString *(*)(id, SEL,NSString*)) objc_msgSend;
id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
id (*action)(id, SEL, NSInteger) = (id(*)(id, SEL, NSInteger)) objc_msgSend;

2.1.如果不用函数原型强转,真机运行会奔溃,模拟器是正常的,
现象:


image.png

原因:指令集不同,必须定义原型才可以使用。
修改成如下即可:

id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
image.png

3.如何获取页面里属性声明的类型

//获取属性类型
+(NSString *)getPropertyType:(NSString *)property inCon:(id)toCon{
    //获取对象的类型objc_getClass("UserModel")
    objc_property_t p = class_getProperty([toCon class], property.UTF8String);
//    const char *name = property_getAttributes(p);
//    NSLog(@"%s==",name);
    // 2.成员类型
    NSString *attrs = @(property_getAttributes(p));
    NSUInteger dotLoc = [attrs rangeOfString:@","].location;
    NSString *code = nil;
    NSUInteger loc = 3;
    if (dotLoc == NSNotFound) { //
        code = [attrs substringFromIndex:loc];
    } else {
        code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc-1)];
    }
//    NSLog(@"%@===%@====",code,attrs);
    return code;
}


//使用
NSString *key =  @“type”;
Class classCon = NSClassFromString(className);
id =  toCon= [[classCon alloc] init];
NSString *objType = [HuControllerId getPropertyType:key inCon:toCon];
                                if ([objType hasSuffix:@"NSString"]) {
                                    id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), paramOne);
                                }else if([objType hasSuffix:@"CGFloat"]){
                                    CGFloat vale = [val doubleValue];
                                    id (*action)(id, SEL, CGFloat) = (id(*)(id, SEL, CGFloat)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), vale);
                                }

3.1如果类型不匹配程序就会奔溃
如果value是Number,但是类型定义的是NSString,如下调用就会奔溃

 if ([value isKindOfClass:[NSNumber class]]) {
                NSInteger val = [(NSNumber *) value integerValue];
                void (*action)(id, SEL, NSInteger) = (void (*)(id, SEL, NSInteger)) objc_msgSend;
                action(toCon, method, val);
            }

修改成如下即可

            //等价于controller.shuxing = value;
            if ([value isKindOfClass:[NSNumber class]] && ![[HuControllerId getPropertyType:key inCon:toCon] isEqualToString:@"NSString"]) {
                NSInteger val = [(NSNumber *) value integerValue];
                void (*action)(id, SEL, NSInteger) = (void (*)(id, SEL, NSInteger)) objc_msgSend;
                action(toCon, method, val);
            } else {
                void (*action)(id, SEL, id) = (void (*)(id, SEL, id)) objc_msgSend;
                action(toCon, method, value);
            }

4.用如上运行时命令 实现不需要引入头文件的页面获取

#import <Foundation/Foundation.h>
@interface HuControllerId : NSObject
+ (HuControllerId *)HuControllerShare;
/**
 指定页面跳转 (不含埋点数据)
 
 @param fromCon 指定页面
 @param conName 页面类
 @param type 页面类型
 @param paramDic 相关参数
 */
- (void)pushFromController:(UIViewController *)fromCon toConName:(NSString *)conName paramType:(HuPushControllerType)type param:(NSDictionary *)paramDic;
/**
 获取指定名字的类对象
 
 @param conName 类名
 @param type 页面类型
 @param paramDic 相关参数
 @return 类对象
 */
- (UIViewController *)getViewControllerWithConName:(NSString *)conName paramType:(HuPushControllerType)type param:(NSDictionary *)paramDic;
@end


#import "HuControllerId.h"
#import <objc/message.h>
@interface HuControllerId ()
@end
@implementation HuControllerId
static HuControllerId *instence = nil;
+ (HuControllerId *)HuControllerShare {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instence = [[HuControllerId alloc] init];
    });
    return instence;
}

- (void)pushFromController:(UIViewController *)fromCon toConName:(NSString *)conName paramType:(HuPushControllerType)type param:(NSDictionary *)paramDic{
    if (!conName || conName.length == 0) {
        return;
    }
    //根据定义好的pageId,拿到类名的字符串
    NSString *className = conName;
    //根据类名转化为Class类型
    Class classCon = NSClassFromString(className);
    //初始化并分配内存
    id toCon;
    //根据HuPushControllerType判断是否有值传到下一页
    switch (type) {
        case HuPushNoParam: {
            toCon= [[classCon alloc] init];
        } break;
        case HuPushProperty: {
            toCon= [[classCon alloc] init];
            [self getToConFromProperty:paramDic toCon:toCon];
        } break;
        case HuPushInit: {
            toCon = [self getToConFromInit:paramDic classCon:classCon];
        } break;
        case HuPushOther: {
            toCon = [self getToConFromInit:paramDic classCon:classCon];
            [self getToConFromProperty:paramDic toCon:toCon];
        } break;
        default:
            break;
    }
    if (toCon) {
        [fromCon.navigationController pushViewController:toCon animated:YES];
    }
}
- (UIViewController *)getViewControllerWithConName:(NSString *)conName paramType:(HuPushControllerType)type param:(NSDictionary *)paramDic{
    if (!conName || conName.length == 0) {
        return nil;
    }
    
    //根据定义好的pageId,拿到类名的字符串
    NSString *className = conName;
    //根据类名转化为Class类型
    Class classCon = NSClassFromString(className);
    //初始化并分配内存
    id toCon;
    //根据HuPushControllerType判断是否有值传到下一页
    switch (type) {
        case HuPushNoParam: {
            toCon= [[classCon alloc] init];
        } break;
        case HuPushProperty: {
            toCon= [[classCon alloc] init];
            [self getToConFromProperty:paramDic toCon:toCon];
        } break;
        case HuPushInit: {
            toCon = [self getToConFromInit:paramDic classCon:classCon];
        } break;
        case HuPushOther: {
            toCon = [self getToConFromInit:paramDic classCon:classCon];
            [self getToConFromProperty:paramDic toCon:toCon];
        } break;
        default:
            break;
    }
    if (toCon) {
        return toCon;
    }
    return  nil;
}
- (id)getToConFromInit:(NSDictionary *)paramDic classCon:(Class)classCon {
    id toCon = nil;
    NSDictionary *initDic = [paramDic valueForKey:HuInitWith];
    NSString *key = [initDic allKeys].firstObject;
    //把OC的字符串改成C语言的字符串
    const char *ky = [key UTF8String];
    NSArray *value = [initDic valueForKey:key];
    //这里判断value数组元素个数是否和key按:分割成数组后的个数相等
    if ([key containsString:@":"] && value) {
        if ([key componentsSeparatedByString:@":"].count == (value.count + 1)) {
            switch (value.count) {
                    case 1: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramOne =  [value objectAtIndex:0];
                            if ([paramOne isKindOfClass:[NSNumber class]]) {
                                NSString *val = [(NSNumber *) paramOne stringValue];
                                NSString *objType = [HuControllerId getPropertyType:key inCon:classAlloc];
                                if ([objType hasSuffix:@"NSString"]) {
                                    id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), paramOne);
                                }else if([objType hasSuffix:@"CGFloat"]){
                                    CGFloat vale = [val doubleValue];
                                    id (*action)(id, SEL, CGFloat) = (id(*)(id, SEL, CGFloat)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), vale);
                                }else{
                                    id (*action)(id, SEL, NSInteger) = (id(*)(id, SEL, NSInteger)) objc_msgSend;
                                    //等价于[[class alloc] iniWith:]
                                    toCon = action(classAlloc, sel_registerName(ky), [val integerValue]);
                                }
                                
                            }else{
                                id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne);
                            }
                            
                        }
                    } break;
                    case 2: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramOne = [value objectAtIndex:0];
                            id paramTwo = [value objectAtIndex:1];
                            
                            if ([paramTwo isKindOfClass:[NSNumber class]]) {
                                id (*action)(id, SEL, id, NSInteger) = (id(*)(id, SEL, id, NSInteger)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne, [paramTwo integerValue]);
                            }else{
                                id (*action)(id, SEL, id, id) = (id(*)(id, SEL, id, id)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne, paramTwo);
                            }
    
                        }
                    } break;
                    case 3: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramTwo = [value objectAtIndex:1];
                            id paramThree = [value objectAtIndex:2];
                            if ([paramTwo isKindOfClass:[NSNumber class]]) {
                                if ([paramThree isKindOfClass:[NSNumber class]]) {
                                    id (*action)(id, SEL, id, NSInteger, NSInteger) = (id(*)(id, SEL, id, NSInteger, NSInteger)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [[value objectAtIndex:1] integerValue], [[value objectAtIndex:2] integerValue]);
                                }else{
                                    id (*action)(id, SEL, id, NSInteger, id) = (id(*)(id, SEL, id, NSInteger, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [[value objectAtIndex:1] integerValue], [value objectAtIndex:2]);
                                }
                                
                            }else{
                                if ([paramThree isKindOfClass:[NSNumber class]]) {
                                    id (*action)(id, SEL, id, id, NSInteger) = (id(*)(id, SEL, id, id, NSInteger)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [[value objectAtIndex:2] integerValue]);
                                }else{
                                    id (*action)(id, SEL, id, id, id) = (id(*)(id, SEL, id, id, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [value objectAtIndex:2]);
                                }
                            }
                        }
                    } break;
                    case 4: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id (*action)(id, SEL, id, id, id, id) = (id(*)(id, SEL, id, id, id, id)) objc_msgSend;
                            toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [value objectAtIndex:2], [value objectAtIndex:3]);
                        }
                    } break;
                default:
                    break;
            }
        }
    }
    return toCon;
}

- (void)getToConFromProperty:(NSDictionary *)paramDic toCon:(id)toCon {
    //需要属性传值,则通过运行时来解决
    if (!toCon) {
        return;
    }
    NSDictionary *propertyDic = [paramDic valueForKey:HuProperty];
    NSArray *keyArr = [propertyDic allKeys];
    for (int i = 0; i < keyArr.count; i++) {
        NSString *key = [keyArr objectAtIndex:i];
        id value = [propertyDic valueForKey:key];
        //把key的首字母大写
        NSString *firstStr = [key substringWithRange:NSMakeRange(0, 1)].uppercaseString;
        NSString *restStr = [key substringFromIndex:1];
        //生成对应属性的set方法
        NSString *selName = [NSString stringWithFormat:@"set%@%@:", firstStr, restStr];
        SEL method = NSSelectorFromString(selName);
        if ([toCon respondsToSelector:method]) {
            //等价于controller.shuxing = value;
            if ([value isKindOfClass:[NSNumber class]] && ![[HuControllerId getPropertyType:key inCon:toCon] isEqualToString:@"NSString"]) {
                NSInteger val = [(NSNumber *) value integerValue];
                void (*action)(id, SEL, NSInteger) = (void (*)(id, SEL, NSInteger)) objc_msgSend;
                action(toCon, method, val);
            } else {
                void (*action)(id, SEL, id) = (void (*)(id, SEL, id)) objc_msgSend;
                action(toCon, method, value);
            }
        }
    }
}

- (id)getToConFromInit:(NSDictionary *)paramDic classCon:(Class)classCon {
    id toCon = nil;
    NSDictionary *initDic = [paramDic valueForKey:HuInitWith];
    NSString *key = [initDic allKeys].firstObject;
    //把OC的字符串改成C语言的字符串
    const char *ky = [key UTF8String];
    NSArray *value = [initDic valueForKey:key];
    //这里判断value数组元素个数是否和key按:分割成数组后的个数相等
    if ([key containsString:@":"] && value) {
        if ([key componentsSeparatedByString:@":"].count == (value.count + 1)) {
            switch (value.count) {
                    case 1: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramOne =  [value objectAtIndex:0];
                            if ([paramOne isKindOfClass:[NSNumber class]]) {
                                NSString *val = [(NSNumber *) paramOne stringValue];
                                NSString *objType = [HuControllerId getPropertyType:key inCon:classAlloc];
                                if ([objType hasSuffix:@"NSString"]) {
                                    id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), paramOne);
                                }else if([objType hasSuffix:@"CGFloat"]){
                                    CGFloat vale = [val doubleValue];
                                    id (*action)(id, SEL, CGFloat) = (id(*)(id, SEL, CGFloat)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), vale);
                                }else{
                                    id (*action)(id, SEL, NSInteger) = (id(*)(id, SEL, NSInteger)) objc_msgSend;
                                    //等价于[[class alloc] iniWith:]
                                    toCon = action(classAlloc, sel_registerName(ky), [val integerValue]);
                                }
                                
                            }else{
                                id (*action)(id, SEL, id) = (id(*)(id, SEL, id)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne);
                            }
                            
                        }
                    } break;
                    case 2: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramOne = [value objectAtIndex:0];
                            id paramTwo = [value objectAtIndex:1];
                            
                            if ([paramTwo isKindOfClass:[NSNumber class]]) {
                                id (*action)(id, SEL, id, NSInteger) = (id(*)(id, SEL, id, NSInteger)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne, [paramTwo integerValue]);
                            }else{
                                id (*action)(id, SEL, id, id) = (id(*)(id, SEL, id, id)) objc_msgSend;
                                toCon = action(classAlloc, sel_registerName(ky), paramOne, paramTwo);
                            }
    
                        }
                    } break;
                    case 3: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id paramTwo = [value objectAtIndex:1];
                            id paramThree = [value objectAtIndex:2];
                            if ([paramTwo isKindOfClass:[NSNumber class]]) {
                                if ([paramThree isKindOfClass:[NSNumber class]]) {
                                    id (*action)(id, SEL, id, NSInteger, NSInteger) = (id(*)(id, SEL, id, NSInteger, NSInteger)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [[value objectAtIndex:1] integerValue], [[value objectAtIndex:2] integerValue]);
                                }else{
                                    id (*action)(id, SEL, id, NSInteger, id) = (id(*)(id, SEL, id, NSInteger, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [[value objectAtIndex:1] integerValue], [value objectAtIndex:2]);
                                }
                                
                            }else{
                                if ([paramThree isKindOfClass:[NSNumber class]]) {
                                    id (*action)(id, SEL, id, id, NSInteger) = (id(*)(id, SEL, id, id, NSInteger)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [[value objectAtIndex:2] integerValue]);
                                }else{
                                    id (*action)(id, SEL, id, id, id) = (id(*)(id, SEL, id, id, id)) objc_msgSend;
                                    toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [value objectAtIndex:2]);
                                }
                            }
                        }
                    } break;
                    case 4: {
                        id classAlloc = ((id (*) (id, SEL))objc_msgSend)(classCon, sel_registerName("alloc"));
                        if ([classAlloc respondsToSelector:sel_registerName(ky)]) {
                            id (*action)(id, SEL, id, id, id, id) = (id(*)(id, SEL, id, id, id, id)) objc_msgSend;
                            toCon = action(classAlloc, sel_registerName(ky), [value objectAtIndex:0], [value objectAtIndex:1], [value objectAtIndex:2], [value objectAtIndex:3]);
                        }
                    } break;
                default:
                    break;
            }
        }
    }
    return toCon;
}

@end

4.1 以下常见的几种使用方法
a.HuPushNoParam

UIViewController *vc = [[HuControllerId HuControllerShare] getViewControllerWithConName:@“HuWorkerSatisfactionViewController" paramType:HuPushNoParam param:nil];
[nav pushViewController:vc animated:YES];

原来需要引入头文件

#import “HuWorkerSatisfactionViewController.h"
 UINavigationController *nav = [[_customVc childViewControllers] objectAtIndex:3];
                    HuWorkerSatisfactionViewController *workerVc = [[HuWorkerSatisfactionViewController alloc] init];
                    [nav pushViewController:workerVc animated:YES];

b.HuPushProperty

NSMutableDictionary *param = @{}.mutableCopy;
    param[@"courseId"] = model.courseId;
    param[@"releaseId"] = model.releaseId;
    param[@"listModel"] = model;
    param[@"byPublicCourseInto"] = @(model.type == 2);
    param[@"needAddMovieTimer"] = @(model.type == 2);
    param[@"byElectiveCoursesInto"] = @(model.type == 3);
    param[@"noDeadlineCourse"] = @(NO);
    param[@"fromMainTrainType"] = @(model.standardLiveTrain);
    //规培不需要累计时间
    if (model.type == 4) {
        param[@"needAddMovieTimer"] = @(NO);
    }else if(model.type == 2){
        param[@"needAddMovieTimer"] = @(YES);
    }
    
    //设置时间是否显示
    if (model.type == 3 && model.trainModel == 0) {
        param[@"noDeadlineCourse"] = @(YES);
    }
    
    [[HuControllerId HuControllerShare]pushFromController:vc toConName:@"HuRegulationTrainDetailNewViewController" paramType:HuPushProperty param:@{HuProperty:param}];

原来需要引入头文件

#import "HuRegulationTrainDetailNewViewController.h"   
HuRegulationTrainDetailNewViewController *detail = [HuRegulationTrainDetailNewViewController new];
    detail.courseId = model.courseId;
    detail.releaseId = model.releaseId;
    detail.listModel = model;
    
    detail.byPublicCourseInto = model.type == 2;
    detail.needAddMovieTimer = model.type == 2;
    detail.byElectiveCoursesInto = model.type == 3;
    detail.noDeadlineCourse = NO;
    detail.fromMainTrainType = model.standardLiveTrain;
    //规培不需要累计时间
    if (model.type == 4) {
        detail.needAddMovieTimer = NO;
    }else if(model.type == 2){
        detail.needAddMovieTimer = YES;
    }
    
    //设置时间是否显示
    if (model.type == 3 && model.trainModel == 0) {
        detail.noDeadlineCourse = YES;
    }
    
    [vc.navigationController pushViewController:detail animated:YES];

c.HuPushInit

vc = [[HuControllerId HuControllerShare]getViewControllerWithConName:@"HuMsgViewController" paramType:HuPushInit param:@{HuInitWith:@{@"initWithType:":@(pageType)}}];

原来用法:

#import "HuMsgViewController.h"
vc = [[HuMsgViewController alloc] initWithType:pageType];

d.HuPushOther

        TrainTestListModel *listModel = [[TrainTestListModel alloc]init];
        listModel.releasePaperId = dic[@"data"][@"releasePaperId"] ?: @"";
        listModel.ID = dic[@"data"][@"releaseStudentId"] ?: @"";
        listModel.paperRecordId = dic[@"data"][@"paperRecordId"] ?: @"";
        listModel.canTest = [dic[@"data"][@"canTakeExam"] boolValue] ? @"1" : @"0";
        [[HuControllerId HuControllerShare] pushFromController:weakSelf.currentVC
                                                     toConName:@"TrainTestReportViewController"
                                                     paramType:HuPushOther
                                                         param:@{ HuInitWith : @{@"initWithModel:WithType:" : @[ listModel, @(HuExamTypeExam) ]},
                                                                  HuProperty : @{@"planEndTime" : [HuCommonMethod timeIntervalWithDateStr:model.endTime]} }];

原来用法:

#import "TrainTestReportViewController.h"
                TrainTestListModel *listModel = [[TrainTestListModel alloc] init];
                listModel.releasePaperId = dic[@"data"][@"releasePaperId"] ?: @"";
                listModel.ID = dic[@"data"][@"releaseStudentId"] ?: @"";
                listModel.paperRecordId = dic[@"data"][@"paperRecordId"] ?: @"";
                listModel.canTest = [dic[@"data"][@"canTakeExam"] boolValue] ? @"1" : @"0";
                TrainTestReportViewController *vc = [[TrainTestReportViewController alloc] initWithModel:listModel WithType:HuExamTypeExam];
                vc.planEndTime = [HuConfigration timeIntervalWithDateStr:model.endTime];
                [curVC.navigationController pushViewController:vc animated:YES];

如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容