iOS底层-类的探索分析之类的属性及类的方法

时间:2021-7-3 作者:qvyue

iOS底层-类的探索分析之isa及继承链中,我们介绍了isa继承链类的结构,现在我们接着分析OC的类。

类的属性与变量

我们运行一下iOS底层-类的探索分析之isa及继承链中的Demo工程,lldb调试下,如图:

iOS底层-类的探索分析之类的属性及类的方法
1

iOS底层-类的探索分析之类的属性及类的方法
2

从上图中,我们拿到了三个ivars,iOS底层-类的探索分析之isa及继承链中我们说过,subject是没有取到,现在取到了,是通过在ro(class_ro_t结构体)里面找到了,那么subjecthobby,name有什么区别呢,我们通过它的定义可以看到,subject是成员变量,而hobby,name是属性,那么它们又有什么不同呢,我们接着往下分析。
我们先贴下代码:

@interface RoPerson : NSObject
{
    NSString *hobby;
    NSObject *objc;
}

@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, strong) NSString *name;
@property (atomic, strong) NSString *aname;

@end

@implementation RoPerson

@end

@interface RoTeacher : NSObject

@end

@implementation RoTeacher

@end

上述代码中,在RoPerson中,我们定义了nickNamenameaname的属性和hobby(字符串类型,基本数据类型是成员变量)的成员变量以及objc(对象类型,也是成员变量,是特殊的一种,叫实例变量)实例变量。
接着我们,执行clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-14.5.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.5.sdk main.m命令编译成c++代码看下底层代码结构,我们打开main.cpp并搜索RoPerson,如图所示:

iOS底层-类的探索分析之类的属性及类的方法
3

iOS底层-类的探索分析之类的属性及类的方法
4

这些属性在底层代码中全部被注释掉了,而属性除了生成了成员变量以外还生成了setter和getter方法。从上图中,我们可以看到nickName的getter方法用的是内存平移,setter方法用的是objc_setProperty,而name使用的也不同,这又是为什么,我们等下再分析。
我们在man.cpp再搜下static struct 找到如下图的代码:

iOS底层-类的探索分析之类的属性及类的方法
5

我们看下**{{(struct objc_selector )”nickName”, “@16@0:8”, (void )_I_RoPerson_nickName}代码

我们解释下@16@0:8(编码,文档参考[Type Encodings]
这个
1 @ id类型
2 16:占用内存
3 @:参数 id
4 0:从0号位置
5 :代表SEL
6 8:从8号位置

void RoObjc_copyIvar_copyProperies(Class pClass){
    
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList(pClass, &count);
    for (unsigned int i=0; i 

上述代码可以用来区分哪些是属性,哪些是成员变量,不再赘述。
现在我们来分析下为什么nickName的属性是objc_setProperty(抽象方法)和内存平移,
先贴下main.m的代码

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        RoPerson *person = [RoPerson alloc];
        person.name = @"Ro";
        RoTeacher *teacher = [RoTeacher alloc];
        Class pClass     = object_getClass(person);        
  
    }
    return 0;
}

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

上文我们说到nickName使用的是objc_setProperty和内存平移,而name不是,我们通过llvm源码分析(这里源码比较难懂,不贴出来了),是因为copy与strong的区别,copy做了特殊处理,默认是strong

类方法归属分析

iOS底层-类的探索分析之isa及继承链中的我们知道类的方法+ (void)say666没找到,我们通过MachoView分析下Demo的macho文件,如图:

iOS底层-类的探索分析之类的属性及类的方法
6

我们从这里可以看到+ (void)say666这个类方法,- (void)sayNB是实例方法,也就是对象方法,是在类里面,避免浪费内存,类方法存储在元类中,比如+ (void)say666,我在定义一个- (void)say666,这时候怎么处理,这也是为什么存在元类中,我们验证下,如图:

iOS底层-类的探索分析之类的属性及类的方法
7
iOS底层-类的探索分析之类的属性及类的方法
8

我们从以下两幅图中,可以看出,类方法就是存储在元类中

void RoObjc_copyMethodList(Class pClass){
    unsigned int count = 0;
    Method *methods = class_copyMethodList(pClass, &count);
    for (unsigned int i=0; i 

以上代码(objc的Api)也可以获取对象方法,类方法的存储。

结语
这篇文章补充了iOS底层-类的探索分析之isa及继承链中的两个疑问点,如有错误,敬请批评指正。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。