美文网首页
首次尝试使用clang来分析iOS类的实现

首次尝试使用clang来分析iOS类的实现

作者: 嗨哒哥 | 来源:发表于2018-07-17 16:55 被阅读0次

    main.m文件编译

    在main文件中敲入如下代码片段

    Account *a = [[Account alloc] init];
    Person *p = [[Person alloc] initWithName:@"josh" age:28 sex:SEX_Male account:a];
    [p addtarget];
    [a setValue:@100 forKeyPath:@"money"];
    NSMutableArray *muArr = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
    [muArr addObject:@"666666"];
    

    打开终端,进入到main文件所在位置,然后输入“clang -rewrite-objc main.m”对main文件进行编译,编译后会发现一些__OBJC_RW_DLLIMPORT消息

    __OBJC_RW_DLLIMPORT void objc_msgSend(void);Sends a message with a simple return value to an instance of a class.向类的实例发送带有简单返回值的消息。
    id objc_msgSend(id self, SEL op, ...);
    self A pointer that points to the instance of the class that is to receive the message 指向接收消息的类实例的指针
    op The selector of the method that handles the message.处理消息的方法的选择器。
    
    
    __OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);Sends a message with a simple return value to the superclass of an instance of a class.向类的一个实例的超类发送一个简单返回值的消息。
    id objc_msgSendSuper(struct objc_super *super, SEL op, ...);
    super A pointer to an objc_super data structure. Pass values identifying the context the message was sent to, including the instance of the class that is to receive the message and the superclass at which to start searching for the method implementation.指向objc_super数据结构的指针。传递值,标识发送消息的上下文,包括接收消息的类的实例和开始搜索方法实现的超类。
    op A pointer of type SEL. Pass the selector of the method that will handle the message.类型为SEL的指针。传递处理消息的方法的选择器。
    
    __OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);Sends a message with a data-structure return value to an instance of a class.向类的实例发送数据结构返回值的消息。
    
    __OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);Sends a message with a data-structure return value to the superclass of an instance of a class.向类实例的超类发送带有数据结构返回值的消息。
    __OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);Sends a message with a floating-point return value to an instance of a class.向类的实例发送带有浮点返回值的消息。
    __OBJC_RW_DLLIMPORT struct objc_class *objc_getClass(const char *);Returns the class definition of a specified class.返回指定类的类。
    __OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass(struct objc_class *);Returns the superclass of a class.返回类的超类。
    __OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass(const char *);Returns the metaclass definition of a specified class.返回指定类的元类。
    __OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);
    __OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);
    __OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);
    __OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);Returns a specified protocol.返回一个指定的协议。
    

    上面的方法会存在于声明的每个类中存在

    接着向下看,会看到如下信息

    struct __block_impl {
      void *isa;指针
      int Flags;标记
      int Reserved;保留位
      void *FuncPtr;
    };
    

    将main.cpp中的找到int main(int argc, const char * argv[]) 会见到

    Account *a = ((Account *(*)(id, SEL))(void *)objc_msgSend)((id)((Account *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Account"), sel_registerName("alloc")), sel_registerName("init"));
    Person *p = ((Person *(*)(id, SEL, NSString *, NSUInteger, SEX, Account *))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("initWithName:age:sex:account:"), (NSString *)&__NSConstantStringImpl__var_folders_5n_5tpcjt9s5s16g65qk472ft1w0000gn_T_main_aadcd9_mi_1, (NSUInteger)28, SEX_Male, (Account *)a);
    ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("addtarget"));
    ((void (*)(id, SEL, id _Nullable, NSString *))(void *)objc_msgSend)((id)a, sel_registerName("setValue:forKeyPath:"), (id _Nullable)((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 100), (NSString *)&__NSConstantStringImpl__var_folders_5n_5tpcjt9s5s16g65qk472ft1w0000gn_T_main_aadcd9_mi_2);
    
    NSMutableArray *muArr = ((NSMutableArray *(*)(id, SEL, ObjectType, ...))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("arrayWithObjects:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5n_5tpcjt9s5s16g65qk472ft1w0000gn_T_main_aadcd9_mi_3, (NSString *)&__NSConstantStringImpl__var_folders_5n_5tpcjt9s5s16g65qk472ft1w0000gn_T_main_aadcd9_mi_4, __null);
    ((void (*)(id, SEL, ObjectType))(void *)objc_msgSend)((id)muArr, sel_registerName("addObject:"), (id)(NSString *)&__NSConstantStringImpl__var_folders_5n_5tpcjt9s5s16g65qk472ft1w0000gn_T_main_aadcd9_mi_5);
    

    再经过编译后的代码中,发现初始化一个Account对象的时候会调用objc_msgSend来发出声明说我要发送消息了,具体发送什么类型的消息还要继续向下看,通过objc_getClass来说明向哪个Class发消息,然后调用sel_registerName来注册alloc、init来完成一个类对象的初始化。

    接下来看下Person类的定义

    在.m文件中

    @interface Person()
    @property (copy, nonatomic) NSString *name;
    @property (assign, nonatomic) SEX sex;
    @property (strong, nonatomic) Account *account;
    @end
    

    在.h文件中

    @interface Person : NSObject
    @property (copy, nonatomic) NSString *name;
    - (void)addtarget;
    - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(SEX)sex account:(Account *)account;
    @end
    

    同样的操作使用clang编译clang -rewrite-objc Person.m:

    struct Person_IMPL {
        struct NSObject_IMPL NSObject_IVARS;
        NSString *_name;
        NSUInteger _age;
        SEX _sex;
        Account *_account;
    };
    

    看到一个类名(Person)+"_"IMPL的结构体,在Person_IMPL中存储着NSObject_IMPL、NSObject_IVARS和定义的成员变量,其中NSObject_IMPL也是一个结构体,里面存放的是isa对象;

    关于Person类中定义的成员变量(包括.m,.h中声明的变量),将会全部放在_ivar_list_t对象里面这个对象里面会有

    static struct /*_ivar_list_t*/ {
        unsigned int entsize;  // sizeof(struct _prop_t)空间大小
        unsigned int count;数量
        struct _ivar_t ivar_list[4];结构体数组
    } _OBJC_$_INSTANCE_VARIABLES_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_ivar_t),
        4,
        {{(unsigned long int *)&OBJC_IVAR_$_Person$_name, "_name", "@\"NSString\"", 3, 8},
         {(unsigned long int *)&OBJC_IVAR_$_Person$_age, "_age", "Q", 3, 8},
         {(unsigned long int *)&OBJC_IVAR_$_Person$_sex, "_sex", "Q", 3, 8},
         {(unsigned long int *)&OBJC_IVAR_$_Person$_account, "_account", "@\"Account\"", 3, 8}}
    };
    struct _ivar_t {
        unsigned long int *offset;  // pointer to ivar offset location偏移量
        const char *name;名称
        const char *type;类型
        unsigned int alignment;
        unsigned int  size;大小
    };
    

    关于Person类中的方法,将会放在_method_list_t对象里面

    static struct /*_method_list_t*/ {
        unsigned int entsize;  // sizeof(struct _objc_method)空间大小
        unsigned int method_count;方法个数
        struct _objc_method method_list[11];存放方法的结构体数组
    } _OBJC_$_INSTANCE_METHODS_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_objc_method),
        11,
        {{(struct objc_selector *)"initWithName:age:sex:account:", "@48@0:8@16Q24Q32@40", (void *)_I_Person_initWithName_age_sex_account_},
        {(struct objc_selector *)"addtarget", "v16@0:8", (void *)_I_Person_addtarget},
        {(struct objc_selector *)"observeValueForKeyPath:ofObject:change:context:", "v48@0:8@16@24@32^v40", (void *)_I_Person_observeValueForKeyPath_ofObject_change_context_},
        {(struct objc_selector *)"name", "@16@0:8", (void *)_I_Person_name},
        {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_Person_setName_},
        {(struct objc_selector *)"age", "Q16@0:8", (void *)_I_Person_age},
        {(struct objc_selector *)"setAge:", "v24@0:8Q16", (void *)_I_Person_setAge_},
        {(struct objc_selector *)"sex", "Q16@0:8", (void *)_I_Person_sex},
        {(struct objc_selector *)"setSex:", "v24@0:8Q16", (void *)_I_Person_setSex_},
        {(struct objc_selector *)"account", "@16@0:8", (void *)_I_Person_account},
        {(struct objc_selector *)"setAccount:", "v24@0:8@16", (void *)_I_Person_setAccount_}}
    };
    
    
    struct _objc_method {
        struct objc_selector * _cmd;
        const char *method_type;方法类型
        void  *_imp;imp指针
    };
    typedef struct objc_selector *SEL;
    

    在Person.h中声明的name变量将会同时存在_ivar_list_t和_prop_list_t中,并且所有的成员变量都会出现在_ivar_list_t结构体中,但是在.h中声明的成员变量只会出现在_prop_list_t,在以后获取某个类的所有成员变量的时候,可以用_ivar_list_t来获取。

    static struct /*_prop_list_t*/ {
        unsigned int entsize;  // sizeof(struct _prop_t)空间大小
        unsigned int count_of_properties;变量个数
        struct _prop_t prop_list[1];
    } _OBJC_$_PROP_LIST_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        sizeof(_prop_t),
        1,
        {{"name","T@\"NSString\",C,N,V_name"}}
    };
    
    struct _protocol_t {
        void * isa;  // NULLisa指针
        const char *protocol_name;协议名称
        const struct _protocol_list_t * protocol_list; // super protocols父类协议列表
        const struct method_list_t *instance_methods;实例方法列表
        const struct method_list_t *class_methods;类方法列表
        const struct method_list_t *optionalInstanceMethods;可选实例方法列表
        const struct method_list_t *optionalClassMethods;可选类方法列表
        const struct _prop_list_t * properties;变量列表
        const unsigned int size;  // sizeof(struct _protocol_t)大小
        const unsigned int flags;  // = 0标志位
        const char ** extendedMethodTypes;
    };
    

    在Person类中,Person类由_method_list_t、_ivar_list_t、_prop_list_t组合而成

    static struct _class_ro_t _OBJC_CLASS_RO_$_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
        0, __OFFSETOFIVAR__(struct Person, _name), sizeof(struct Person_IMPL), 
        (unsigned int)0, 
        0, 
        "Person",
        (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_Person,
        0, 
        (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_Person,
        0, 
        (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Person,
    };
    

    相关文章

      网友评论

          本文标题:首次尝试使用clang来分析iOS类的实现

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