iOS 底层探究:属性与成员变量

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战缓存

1.WWDC 类结构的优化

WWDC关于runtime里面关于类的优化里面提到了clean memorydirty memorymarkdown

1.1 Clean Memory

  • 加载后不会再改变的内存
  • class_ro_t是只读的,属于Clean Memory
  • 可移除,从而节省更多内存空间。若是你有须要,系统能够从磁盘中从新加载。

1.2 Dirty Memory

  • 进程运行时会发生变化的内存
  • 类结构体一旦被使用就是Dirty Memory,由于运行时会写入新的数据,例如:方法缓存
  • Dirty Memory是类数据被分为两部分的缘由

Dirty MemoryClean Memory更昂贵,由于在进程运行的整个过程当中,都须要被保留。经过分离出那些永远不会改变的数据,将大部分的类数据存储为Clean Memory。 类结构一经使用就会变成Dirty Memory,由于运行时会向他写入新的数据,例如建立一个新的方法缓存并从类中指向它。因此class_rw_t出现了,它能够读写类的继承关系,跟踪类的方法,属性,协议等,单只有大约10%的类会去修改它的方法,因此class_rw_ext_t出现了,90%内将不须要class_rw_ext_t,这能节省class_rw_t一半的空间。以下图app

image.png

2.属性和成员变量

在iOS5以前,定义成员变量是在大括号里定义,同时用了@property声明,并且还在@implementation中使用@synthesize方法。缘由是苹果将默认编译器从GCC转换为LLVM(low level virtual machine),才再也不须要为属性声明实例变量了。 在没有更改以前,属性的正常写法须要成员变量+@property+@synthesize成员便利那个三个步骤。更换为LLVM以后,编译器在编译过程当中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。所以如今部门没必要再声明一个实例变量。 如今@property声明的属性不单单给咱们生成一个_类型的成员变量,同时也会生成setter/getter方法。ide

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

2.1 成员变量与属性的区别

  • 成员变量:在底层只是变量的声明
  • 属性:系统会自动在底层添加_属性名变量,同时生成setter和getter方法

2.2 成员变量与实例变量的区别

  • 实例变量是一种特殊的成员变量
  • 成员变量为基本数据类型
  • 实例变量为对象类型,例如:NSObject类型
  • NSString为常量类型,属于成员变量

3.isKindOfClass

3.1方法的做用

不管调用类对象仍是实例对象的isKindOfClass方法,入口函数统一为 objc_opt_isKindOfClass 找到objc_opt_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->getSuperclass()) { 
            if (tcls == otherClass) return YES; 
         } 
         return NO; 
     } 
#endif 
    return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass); 
}
复制代码
  • 获取对象isa指向的类,和传入的Class对比
  • 遍历对象isa指向类的父类,和传入的Class对比

isKindOfClass方法的做用:oop

  • 类对象
    • 元类 VS Class
    • 遍历:类的父类 VS Class
  • 实例对象
    • 类 VS Class
    • 遍历:类的父类 VS Class

3.2验证类对象与实例对象

示例:封装isKindOfClass函数post

void isKindOfClassDemo(){ 
    BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; 
    BOOL re2 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; 
    NSLog(@"NSObject类对象:%hhd", re1); 
    NSLog(@"LGPerson类对象:%hhd", re2); 
    BOOL re3 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; 
    BOOL re4 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; 
    NSLog(@"NSObject实例对象:%hhd", re3); 
    NSLog(@"LGPerson实例对象:%hhd", re4); }
复制代码

调用isKindOfClassDemo函数优化

isKindOfClassDemo(); 
------------------------- 
NSObject类对象:1 
LGPerson类对象:0 
NSObject实例对象:1 
LGPerson实例对象:1
复制代码

3.3分析

  • res1传入的是NSObject的类,获取元类与NSObject不等,继续寻找获取元类的父类为NSObject与传入的值相等,返回true。
    • res2传入的是LGPerson的类,获取元类与LGPerson不等,继续寻找获取元类的父类为NSObject的元类,与传入的值依旧不等,继续往上NSObject元类的父类为NSObject依旧不等,再往上就是nil,最后返回false
  • res3 传入的是NSObject的实例,获取对象的类,与NSObject相等,返回true
  • res4 传入的是LGPerson的实例,获取对象的类,与LGPerson相等,返回true

4 isMemberOfClass

4.1方法的做用

找到isMemberOfClass方法spa

+ (BOOL)isMemberOfClass:(Class)cls { 
    return self->ISA() == cls; 
} 
- (BOOL)isMemberOfClass:(Class)cls { 
    return [self class] == cls; 
}
复制代码
  • 类方法:获取类的元类,和传入的cls对比
  • 实例方法:获取对象所属的类,和传入的cls对比

4.2验证类对象与实例对象

封装isMemberOfClass方法code

void isMemberOfClassDemo(){ 
    BOOL re1 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; 
    BOOL re2 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; 
    NSLog(@"NSObject类对象:%hhd", re1); 
    NSLog(@"LGPerson类对象:%hhd", re2); 
    BOOL re3 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; 
    BOOL re4 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; 
    NSLog(@"NSObject实例对象:%hhd", re3); 
    NSLog(@"LGPerson实例对象:%hhd", re4); 
}
复制代码

调用isMemberOfClassDemo函数

isMemberOfClassDemo(); 
------------------------- 
NSObject类对象:0 
LGPerson类对象:0 
NSObject实例对象:1 
LGPerson实例对象:1
复制代码

4.3分析

  • res1是NSObject类调用类方法isMemberOfClassNSObject类比较,很明显,NSObject的元类NSObject自己并不相等,因此返回false
  • res2是LGPerson类调用类方法isMemberOfClassLGPerson类比较,LGPerson的元类LGPerson自己并不相等,因此返回false
  • res3是NSObject的实例调用实例方法isMemberOfClassNSObject类比较,明显她们是相同的,因此返回true
  • res4是LGPerson的实例调用实例方法isMemberOfClassLGPerson类比较,明显的他们是相同的,因此返回true
相关文章
相关标签/搜索