美文网首页
iOS 底层原理 - 对象的本质

iOS 底层原理 - 对象的本质

作者: yan0_0 | 来源:发表于2020-02-10 01:19 被阅读0次

对象的本质

1.在main.m中准备代码如下

@interface LGPerson : NSObject{
    NSString *name; // 成员变量 : 底层编译不会生成相应的 setter getter
    // lgTeacher *t;    // 实例变量 : 是一种特殊的成员变量 (类声明而来 实例 - id (void *))
}
@property (nonatomic, copy) NSString *name; // 属性的区别
@end

@implementation LGPerson

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"123");
    }
    return 0;
}

通过clang -rewrite-objc main.m -o main.cpp 编译底层源码命令来编译成mian.cpp文件。
2.分析编译生成的main.cpp文件,直接看与LGPerson相关的内容

#ifndef _REWRITER_typedef_LGPerson
#define _REWRITER_typedef_LGPerson
typedef struct objc_object LGPerson;
typedef struct {} _objc_exc_LGPerson;
#endif

extern "C" unsigned long OBJC_IVAR_$_LGPerson$_name;
struct LGPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *name;
    NSString *_name;
};

// @property (nonatomic, copy) NSString *name;
/* @end */


// @implementation LGPerson


static NSString * _I_LGPerson_name(LGPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);

static void _I_LGPerson_setName_(LGPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _name), (id)name, 0, 1); }
// @end

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_jh_7w1wkg8j5w58pf3sv2s3pzvr0000gn_T_main_e4cb5b_mi_0);
    }
    return 0;
}

可以看出在底层生成了一个结构体,对象的本质就是结构体
struct LGPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *name;
NSString _name;
};
成员 NSObject_IMPL 只包含一个isa,
struct NSObject_IMPL {
Class isa;
};
成员name,是我们类里面的成员变量。
成员name,是我们类里面的属性,编译成了带有下划线的成员。
static NSString * _I_LGPerson_name(LGPerson * self, SEL _cmd) { return (
(NSString **)((char *)self + OBJC_IVAR__LGPerson_name)); },
这个函数实际上就是getter方法,包含两个默认参数self、_cmd。
static void I_LGPerson_setName(LGPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, OFFSETOFIVAR(struct LGPerson, _name), (id)name, 0, 1); }
函数I_LGPerson_setName,实际上就是setter方法,包含两个默认参数self、cmd,与一个形参name。
从上可以看出成员变量与属性的区别,属性会用
修饰,而且会有setter和getter方法
3.析method_list_t结构体

static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[2];
} _OBJC_$_INSTANCE_METHODS_LGPerson __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    2,
    {{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LGPerson_name},
    {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LGPerson_setName_}}
};

我们分析一下这两个objc_selector

{{(struct objc_selector *)"name", "@16@0:8", (void *)_I_XDPerson_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)I_XDPerson_setName}}

两个都是由SEL->selector,type方法签名,imp函数实现组成。与上面的setter和getter方法对应

type方法签名介绍:

我们拿v24@0:8@16分析:

第一个符号v返回值类型,24返回值类型的长度。
第二个符号@参数一类型对象,0长度0-7。
第三个符号:参数二类型SEL,8长度8-15。
第四个符号@参数三类型对象,16长度16-23。

我们可以直接通过苹果官网TypeEncode或者在Xcode中在@Encodecommond+shift+0来查看。

相关文章

网友评论

      本文标题:iOS 底层原理 - 对象的本质

      本文链接:https://www.haomeiwen.com/subject/zvpoxhtx.html