这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
1.WWDC 类结构的优化
在WWDC关于runtime里面关于类的优化里面提到了clean memory,dirty memory
1.1 Clean Memory
- 加载后不会再改变的内存
class_ro_t是只读的,属于Clean Memory- 可移除,从而节省更多内存空间。如果你有需要,系统可以从磁盘中重新加载。
1.2 Dirty Memory
- 进程运行时会发生变化的内存
- 类结构体一旦被使用就是
Dirty Memory,因为运行时会写入新的数据,例如:方法缓存 Dirty Memory是类数据被分为两部分的原因Dirty Memory比Clean Memory更昂贵,因为在进程运行的整个过程中,都需要被保留。通过分离出那些永远不会改变的数据,将大部分的类数据存储为Clean Memory。 类结构一经使用就会变成Dirty Memory,因为运行时会向他写入新的数据,例如创建一个新的方法缓存并从类中指向它。所以class_rw_t出现了,它可以读写类的继承关系,跟踪类的方法,属性,协议等,单只有大约10%的类会去修改它的方法,所以class_rw_ext_t出现了,90%内将不需要class_rw_ext_t,这能节省class_rw_t一半的空间。如下图
2.属性和成员变量
在iOS5之前,定义成员变量是在大括号里定义,同时用了@property声明,而且还在@implementation中使用@synthesize方法。原因是苹果将默认编译器从GCC转换为LLVM(low level virtual machine),才不再需要为属性声明实例变量了。
在没有更改之前,属性的正常写法需要成员变量+@property+@synthesize成员便利那个三个步骤。更换为LLVM之后,编译器在编译过程中发现没有新的实例变量后,就会生成一个下划线开头的实例变量。因此现在部门不必再声明一个实例变量。
现在@property声明的属性不仅仅给我们生成一个_类型的成员变量,同时也会生成setter/getter方法。
- 属性=带下划线成员变量+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方法的作用:
- 类对象
- 元类 VS Class
- 遍历:类的父类 VS Class
- 实例对象
- 类 VS Class
- 遍历:类的父类 VS Class
3.2验证类对象与实例对象
示例:封装isKindOfClass函数
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
- res2传入的是
- res3 传入的是
NSObject的实例,获取对象的类,与NSObject相等,返回true - res4 传入的是
LGPerson的实例,获取对象的类,与LGPerson相等,返回true
4 isMemberOfClass
4.1方法的作用
找到isMemberOfClass方法
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
- 类方法:获取类的元类,和传入的cls对比
- 实例方法:获取对象所属的类,和传入的cls对比
4.2验证类对象与实例对象
封装isMemberOfClass方法
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类调用类方法isMemberOfClass与NSObject类比较,很明显,NSObject的元类与NSObject本身并不相等,所以返回false - res2是
LGPerson类调用类方法isMemberOfClass与LGPerson类比较,LGPerson的元类与LGPerson本身并不相等,所以返回false - res3是
NSObject的实例调用实例方法isMemberOfClass与NSObject类比较,明显她们是相同的,所以返回true - res4是
LGPerson的实例调用实例方法isMemberOfClass与LGPerson类比较,明显的他们是相同的,所以返回true