iOS-底层原理05-类的结构分析

《iOS底层原理文章汇总》

类中为什么没有成员变量和类方法,它们在哪里获取???

属性,成员变量和实例变量的区分

  • 1.clang编译main.m文件:clang -rewrite-objc main.m -o main.cpp得到main.cpp文件
@interface DCPerson :NSObject
{
    NSString *hobby;
    NSObject *objc;
}
@property(nonatomic,copy)NSString *nickName;
@property(nonatomic,strong)NSString *name;
@end

@implementation DCPerson
@end
成员变量、setter和getter方法@2x.png

属性=带下划线的成员变量+setter+getter方法
实例变量:特殊的成员变量(类的实例化)

获取成员变量(hobby)
成员变量都在class_ro_t中,class_ro_t中的ivars,获取成员变量

class_ro_t@2x.png
ivars@2x.png
(lldb) p/x DCPerson.class
(Class) $0 = 0x00000001000022c0 DCPerson
(lldb) p (class_data_bits_t *)0x00000001000022e0
(class_data_bits_t *) $1 = 0x00000001000022e0
(lldb) p $1->data()
(class_rw_t *) $2 = 0x000000010067c5d0
(lldb) p *$2
(class_rw_t) $3 = {
  flags = 2148007936
  witness = 0
  ro_or_rw_ext = {
    std::__1::atomic<unsigned long> = 4294975680
  }
  firstSubclass = DCTeacher
  nextSiblingClass = NSUUID
}
(lldb) p $3.ro()
(const class_ro_t *) $4 = 0x00000001000020c0
(lldb) p *$4
(const class_ro_t) $5 = {
  flags = 388
  instanceStart = 8
  instanceSize = 24
  reserved = 0
  ivarLayout = 0x0000000100000f70 "\x02"
  name = 0x0000000100000f67 "DCPerson"
  baseMethodList = {
    ptr = 0x0000000100002108
  }
  baseProtocols = 0x0000000000000000
  ivars = 0x0000000100002170
  weakIvarLayout = 0x0000000000000000
  baseProperties = 0x00000001000021b8
  _swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $5.ivars
(const ivar_list_t *const) $6 = 0x0000000100002170
(lldb) p *$6
(const ivar_list_t) $7 = {
  entsize_list_tt<ivar_t, ivar_list_t, 0, PointerModifierNop> = (entsizeAndFlags = 32, count = 2)
}
(lldb) p $7.get(0)
(ivar_t) $8 = {
  offset = 0x0000000100002288
  name = 0x0000000100000ef2 "hobby"
  type = 0x0000000100000f84 "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) p $7.get(1)
(ivar_t) $9 = {
  offset = 0x0000000100002290
  name = 0x0000000100000ef8 "_kc_name"
  type = 0x0000000100000f84 "@\"NSString\""
  alignment_raw = 3
  size = 8
}
(lldb) p $7.get(2)
Assertion failed: (i < count), function get, file /Users/cloud/Documents/iOS/0914/0914练习/iOS-isa指针/runtime/objc-runtime-new.h, line 479.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
12.gif
  • 2.属性怎么生成setter和getter方法?调用objc_setProperty
  • 3.为什么 copy和strong修饰属性有区别,设计到llvm
  • 4.typeEncodeUrl表示
void lgTypes(){
    NSLog(@"char --> %s",@encode(char));
    NSLog(@"int  --> %s",@encode(int));
    NSLog(@"short  --> %s",@encode(short));
    NSLog(@"long  --> %s",@encode(long));
    NSLog(@"long long  --> %s",@encode(long long));
    NSLog(@"unsigned char --> %s",@encode(unsigned char));
    NSLog(@"unsigned int --> %s",@encode(unsigned int));
    NSLog(@"unsigned short --> %s",@encode(unsigned short));
    NSLog(@"unsigned long --> %s",@encode(unsigned long));
    NSLog(@"float --> %s",@encode(float));
    NSLog(@"bool --> %s",@encode(bool));
    NSLog(@"void --> %s",@encode(void));
    NSLog(@"char * --> %s",@encode(char *));
    NSLog(@"id --> %s",@encode(id));
    NSLog(@"Class --> %s",@encode(Class));
    NSLog(@"SEL --> %s",@encode(SEL));
    int array[] = {1,2,3};
    NSLog(@"int[] --> %s",@encode(typeof(array)));
    typedef struct person{
        char *name;
        int age;
    } Person;
    NSLog(@"struct --> %s",@encode(Person));
    
    typedef union union_type{
        char *name;
        int a;
    }Union;
    NSLog(@"union --> %s",@encode(Union));
    
    int a = 2;
    int *b = {&a};
    NSLog(@"int[] --> %s",@encode(typeof(b)));
}
//输出
2020-10-05 20:27:27.382751+0800 iOS-isa分析[27629:3706131] char --> c
2020-10-05 20:27:27.382783+0800 iOS-isa分析[27629:3706131] int  --> i
2020-10-05 20:27:27.382809+0800 iOS-isa分析[27629:3706131] short  --> s
2020-10-05 20:27:27.384252+0800 iOS-isa分析[27629:3706131] long  --> q
2020-10-05 20:27:27.384306+0800 iOS-isa分析[27629:3706131] long long  --> q
2020-10-05 20:27:27.384342+0800 iOS-isa分析[27629:3706131] unsigned char --> C
2020-10-05 20:27:27.384373+0800 iOS-isa分析[27629:3706131] unsigned int --> I
2020-10-05 20:27:27.392859+0800 iOS-isa分析[27629:3706131] unsigned short --> S
2020-10-05 20:27:27.392903+0800 iOS-isa分析[27629:3706131] unsigned long --> Q
2020-10-05 20:27:27.392931+0800 iOS-isa分析[27629:3706131] float --> f
2020-10-05 20:27:27.392957+0800 iOS-isa分析[27629:3706131] bool --> B
2020-10-05 20:27:27.393086+0800 iOS-isa分析[27629:3706131] void --> v
2020-10-05 20:27:27.393117+0800 iOS-isa分析[27629:3706131] char * --> *
2020-10-05 20:27:27.393262+0800 iOS-isa分析[27629:3706131] id --> @
2020-10-05 20:27:27.394643+0800 iOS-isa分析[27629:3706131] Class --> #
2020-10-05 20:27:27.394705+0800 iOS-isa分析[27629:3706131] SEL --> :
2020-10-05 20:27:27.394750+0800 iOS-isa分析[27629:3706131] int[] --> [3i]
2020-10-05 20:27:27.394815+0800 iOS-isa分析[27629:3706131] struct --> {person=*i}
2020-10-05 20:27:27.394869+0800 iOS-isa分析[27629:3706131] union --> (union_type=*i)
2020-10-05 20:27:27.394990+0800 iOS-isa分析[27629:3706131] int[] --> ^i
method_types@2x.png

typeEncodingUrl

TypeEncodingUrl@2x.png

nickName的getter方法@16@0:8分别表示什么???
查看nickName的getter方法得到,每个方法都默认自带了两个参数(id self,SEL _cmd)

static NSString * _I_DCPerson_nickName(DCPerson * self, SEL _cmd) 
{ return (*(NSString **)((char *)self + OBJC_IVAR_$_DCPerson$_nickName)); }

@------>函数的返回值

16----->参数共占用16个字节

@------>第一个参数的类型 id 8字节

0------>第一个参数从0开始

:------>第二个参数为SEL 8字节 从8号位开始

8------>第二个参数从第8字节开始

setName的函数的类型为v24@0:8@16,分别表示如下

v------>函数类型为无返回值

24----->参数共占用24个字节

@------>第一个参数的类型 id 8字节

0------>第一个参数从0开始

:------>第二个参数为SEL 8字节 从8号位开始

8------>第二个参数从第8字节位置开始

@------>第三个参数为类型为对象 从第16字节开始

16----->第三个参数从第16字节位置开始

static void _I_DCPerson_setName_(DCPerson * self, SEL _cmd, NSString *name) 

{ (*(NSString **)((char *)self + OBJC_IVAR_$_DCPerson$_name)) = name; }

为什么没有获取到类方法呢???

  • 1.MachOView,通过工具查看编译后的工具,Cmd + B编译后将exe文件拖到MachOView中查看编译结果
MachOView查看内存@2x.png
13.gif

若不再编译DCTeacher,则不回加载到内存中,注释掉DCTeacher的初始化,内存中不再有DCTeacher的类信息

        //0x00007ffffffffff8ULL
        //class_data_bits_t
        DCPerson *person = [DCPerson alloc];
        object_getClass(person);
//        DCTeacher *teacher = [DCTeacher alloc];
        DCNSLog(@"%@---%p-----%p",person,person,&person);
//        DCNSLog(@"%@---%p-----%p",teacher,teacher,&teacher);
14.gif
  • 2.若是App呢,能读取到App中所有的方法
15.gif
App获取所有的方法@2x.png

类方法到底存在哪儿呢???

  • 1.通过lldb调试

lldb调试类方法-既然不存在类中,那就往上一级查找方法

(lldb) p/x DCPerson.class
(Class) $0 = 0x00000001000022c0 DCPerson
(lldb) x/4gx 0x00000001000022c0
0x1000022c0: 0x0000000100002298 0x0000000100336140
0x1000022d0: 0x00000001003303d0 0x0000802400000000
(lldb) p/x 0x0000000100002298 & 0x00007ffffffffff8ULL
(unsigned long long) $1 = 0x0000000100002298
(lldb) p (class_data_bits_t *)0x00000001000022b8
(class_data_bits_t *) $2 = 0x00000001000022b8
(lldb) p $2->data()
(class_rw_t *) $3 = 0x0000000101116e20
(lldb) p $3->methods()
(const method_array_t) $4 = {
  list_array_tt<method_t, method_list_t, method_list_t_authed_ptr> = {
     = {
      list = {
        ptr = 0x00000001000020a0
      }
      arrayAndFlag = 4294975648
    }
  }
}
(lldb) p $4.list.ptr
(method_list_t *const) $5 = 0x00000001000020a0
(lldb) p *$5
(method_list_t) $6 = {
  entsize_list_tt<method_t, method_list_t, 4294901763, method_t::pointer_modifier> = (entsizeAndFlags = 26, count = 1)
}
(lldb) p $6.get(0)
(method_t) $7 = {}
(lldb) p $7.name()
(SEL) $8 = "say666"
(lldb) p $7.types()
(const char *) $9 = 0x0000000100000f77 "v16@0:8"
(lldb) p $6.get(1)
Assertion failed: (i < count), function get, file /Users/cloud/Documents/iOS/0914/0914练习/iOS-isa指针/runtime/objc-runtime-new.h, line 479.
error: Execution was interrupted, reason: signal SIGABRT.
The process has been returned to the state before expression evaluation.
16.gif
  • 2.通过方法打印
void lgObjc_copyMethodList(Class pClass){
    unsigned int count = 0;
    Method *methods = class_copyMethodList(pClass, &count);
    for (unsigned int i=0; i<count; i++) {
        Method const method = methods[i];
        //获取方法名
        NSString *key = NSStringFromSelector(method_getName(method));
        DCNSLog(@"%s --- Method,name:%@",__func__,key);
    }
    free(methods);
}

void lgInstanceMethod_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getInstanceMethod(pClass, @selector(sayHello));
    Method method2 = class_getInstanceMethod(metaClass, @selector(sayHello));
    
    Method method3 = class_getInstanceMethod(pClass, @selector(sayHappy));
    Method method4 = class_getInstanceMethod(metaClass, @selector(sayHappy));
    
    DCNSLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

void lgClassMethod_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    Method method1 = class_getClassMethod(pClass, @selector(sayHello));
    Method method2 = class_getClassMethod(metaClass, @selector(sayHello));
    
    Method method3 = class_getClassMethod(pClass, @selector(sayHappy));
    Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));
    
    DCNSLog(@"%s - %p-%p-%p-%p",__func__,method1,method2,method3,method4);
}

void lgIMP_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
    IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
    
    IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
    
    DCNSLog(@"%s - %p-%p-%p-%p",__func__,imp1,imp2,imp3,imp4);
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        DCPerson *person = [DCPerson alloc];
        Class pClass = object_getClass(person);
        lgObjc_copyMethodList(pClass);
        
        lgInstanceMethod_classToMetaclass(pClass);
        lgClassMethod_classToMetaclass(pClass);
    }
    return 0;
}
//输出
lgObjc_copyMethodList --- Method,name:sayHello
lgInstanceMethod_classToMetaclass - 0x100003100-0x0-0x0-0x100003098
lgClassMethod_classToMetaclass - 0x0-0x0-0x100003098-0x100003098

面试题:为什么元类中含有类方法呢???

Method method4 = class_getClassMethod(metaClass, @selector(sayHappy));

返回true。

Method class_getClassMethod(Class cls, SEL sel)
{
    if (!cls  ||  !sel) return nil;

    return class_getInstanceMethod(cls->getMeta(), sel);
}

    // NOT identical to this->ISA when this is a metaclass
    Class getMeta() {
        if (isMetaClass()) return (Class)this;
        else return this->ISA();
    }

如果是元类,返回本身的实例方法,不会往下一直递归,更加说明类方法为元类的实例方法

17.gif
class_getClassMethod@2x.png

面试题isKindOfClass和isMemberOfClass

        BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL re3 = [(id)[DCPerson class] isKindOfClass:[DCPerson class]];
        BOOL re4 = [(id)[DCPerson class] isMemberOfClass:[DCPerson class]];
        NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
        
        BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
        BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
        BOOL re7 = [(id)[DCPerson alloc] isKindOfClass:[DCPerson class]];
        BOOL re8 = [(id)[DCPerson alloc] isMemberOfClass:[DCPerson class]];
        NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
        
//输出
2020-10-06 17:56:22.792804+0800 iOS-类方法归属分析[51580:4486122]  re1 :1
 re2 :0
 re3 :0
 re4 :0
2020-10-06 17:56:22.793425+0800 iOS-类方法归属分析[51580:4486122]  re5 :1
 re6 :1
 re7 :1
 re8 :1

BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];分析

这儿调用的是isKindOfClass类方法

//类 VS 元类   ====> NSObject VS NSObject的元类
不相等继续找父类
//类 VS NSObject的根元类 ====> NSObject VS NSObject
循环结束返回true

+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

BOOL re3 = [(id)[DCPerson class] isKindOfClass:[DCPerson class]];分析
这儿调用的也是isKindOfClass类方法

DCPerson VS DCPerson的元类   不相等
DCPerson VS DCPerson的根元类 不相等
DCPerson VS DCObject        不相等
DCPerson VS nil             循环结束 返回false
+ (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = self->ISA(); tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];分析
这儿调用的是isMemberOfClass类方法

NSObject  VS NSObject的元类 不相等 返回false
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

BOOL re4 = [(id)[DCPerson class] isMemberOfClass:[DCPerson class]];分析
这儿调用的也是isMemberOfClass类方法

DCPerson VS DCPerson的元类 不相等 返回false
+ (BOOL)isMemberOfClass:(Class)cls {
    return self->ISA() == cls;
}

BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
调用对象方法isKindOfClass

[NSObject class] VS [NSObject class] 返回true
- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

BOOL re7 = [(id)[DCPerson alloc] isKindOfClass:[DCPerson class]];
调用对象方法isKindOfClass

[DCPerson class] VS [DCPerson class] 返回true
- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}

BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
调用对象方法isMemberOfClass

[NSObject class] VS [NSObject class]  返回true
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

BOOL re8 = [(id)[DCPerson alloc] isMemberOfClass:[DCPerson class]];
调用对象方法isMemberOfClass

[DCPerson class] VS [DCPerson class] 返回true
- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

isKindOfClass类方法:类和元类的继承链进行对比

1.isKindOfClass和isMemberOfClass思维误区,断点以为会走入类方法isKindOfClass中,结果发现并没有走入isKindOfClass类方法中

18.gif

发现走入了BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)方法中

// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
    if (slowpath(!obj)) return NO;
    Class cls = obj->getIsa();
    if (fastpath(!cls->hasCustomCore())) {
        for (Class tcls = cls; tcls; tcls = tcls->superclass) {
            if (tcls == otherClass) return YES;
        }
        return NO;
    }
#endif
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}

        BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]];
        BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]];
        BOOL re3 = [(id)[DCPerson class] isKindOfClass:[DCPerson class]];
        BOOL re4 = [(id)[DCPerson class] isMemberOfClass:[DCPerson class]];
        NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
        
        BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]];
        BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]];
        BOOL re7 = [(id)[DCPerson alloc] isKindOfClass:[DCPerson class]];
        BOOL re8 = [(id)[DCPerson alloc] isMemberOfClass:[DCPerson class]];
        NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
//输出
2020-10-06 20:33:43.487320+0800 iOS-类方法归属分析[46086:4702913]  re1 :1
 re2 :0
 re3 :0
 re4 :0
2020-10-06 20:33:43.492205+0800 iOS-类方法归属分析[46086:4702913]  re5 :1
 re6 :1
 re7 :1
 re8 :1

对象方法存在类里面,类方法存在元类里面

-(void)sayHello;
+(void)sayHappy;
-(void)sayHello{
    NSLog(@"%@",_cmd);
}
+(void)sayHappy{
    NSLog(@"%@",_cmd);
}

void lgIMP_classToMetaclass(Class pClass){
    const char *className = class_getName(pClass);
    Class metaClass = objc_getMetaClass(className);
    
    IMP imp1 = class_getMethodImplementation(pClass, @selector(sayHello));
    IMP imp2 = class_getMethodImplementation(metaClass, @selector(sayHello));
    
    IMP imp3 = class_getMethodImplementation(pClass, @selector(sayHappy));
    IMP imp4 = class_getMethodImplementation(metaClass, @selector(sayHappy));
    
    DCNSLog(@"%s - %p-%p-%p-%p",__func__,imp1,imp2,imp3,imp4);
}
//输出
lgIMP_classToMetaclass - 0x100001cb0-0x1002c2b40-0x1002c2b40-0x100001c50

imp2和imp3按理说应该找不到为0x0,结果为什么不为0x0呢???
查看class_getMethodImplementation源码,找不到方法都会走消息转发流程,return _objc_msgForward。所以imp2和imp3两个地址打印的一样,都走消息转发流程。

IMP class_getMethodImplementation(Class cls, SEL sel)
{
    IMP imp;

    if (!cls  ||  !sel) return nil;

    imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);

    // Translate forwarding function to C-callable external version
    if (!imp) {
        return _objc_msgForward;
    }

    return imp;
}
19.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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