1、代理的效率高,还是KVO的效率高?
代理的效率高,因为代理不会动态的生成类
2、怎么拿到一个对象的类对象,怎么拿到一个类的元类对象
isa指针指向的就是类对象
object_getClass(self.per1) == self.per1.isa
NSLog(@"类对象 %@ %@",
object_getClass(self.per1),
object_getClass(self.per2));
object_getClass(object_getClass(self.per1)) == self.per1.isa.isa
NSLog(@"元类对象 %@ %@",
object_getClass(object_getClass(self.per1)),
object_getClass(object_getClass(self.per2)));
3.1、添加KVO的对象的元类和不添加KVO的对象的元类是否是一个?
不是同一个,添加KVO的元类是 NSKVONotifying_类名
3.2、iOS用什么方式实现一个对象的KVO?(KVO的本质是什么)
比如给Person对象的age属性添加KVO监听
1、利用Runtime生成Person子类<NSKVONotifying_Person
>,并且让对象的isa指针指向NSKVONotifying_Person
2、当修改Person
的age
属性时候,会调用Foundation
的_NSSet***ValueAndNotify
函数
2.1、调用willChangeValueForKey
2.2、调用super
的属性setAge:
方法
2.3、调用didChangeValueForKey
2.3.1、内部调用- (void)observeValueForKeyPath: ofObject:change: context:;
3.3、怎么手动触发KVO监听?
调用对象的
[self.per1 willChangeValueForKey:@"age"];
[self.per1 didChangeValueForKey:@"age"];
3.4、直接修改成员变量会触发KVO吗?
@interface Person : NSObject
{
@public
NSString *_name;
}
/// 名字
@property (nonatomic, copy) NSString * name;
@end
self.per->_name = @"333";
不能,必须要触发set方法,或者【手动触发】KVO才可以,详情见上面。
怎么才能实现,直接修改成员变量,触发KVO呢?
[self.per willChangeValueForKey:@"name"];
self.per->_name = @"333";
[self.per didChangeValueForKey:@"name"];
4.1、KVC setValue: forKeyPath:
的实现原理
4.2、KVC操作能不能触发KVO的监听
@interface Person : NSObject
{
@public
int _age;
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Person *per = [[Person alloc] init];
[per addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[per setValue:@10 forKeyPath:@"age"];
[per removeObserver:self forKeyPath:@"age"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keyPath = %@ %@",keyPath,change);
}
可以触发<满足KVC的任何一种方式都可以触发>,可能调用KVC的时候内部触发了
[per willChangeValueForKey:@"age"];
per->_age = 123;
[per didChangeValueForKey:@"age"];
触发KVO
4.3、KVC valueForKey:
的原理
4.4、怎么给一个属性赋值,并且不触发set方法
@interface Person : NSObject
/// name
@property (nonatomic, copy) NSString * name;
@end
- (void)setName:(NSString *)name {
_name = [name copy];
NSLog(@"触发了set方法 name === %@",_name);
}
Person *per = [[Person alloc] init];
[per setValue:@"123" forKey:@"_name"];
NSLog(@"per.name === %@",per.name);
5、一个NSObject对象占用多少内存
NSObject对象中就一个isa指针,一个指针占用内存的大小(64bit环境下8个字节,32bit环境下4个字节)
5.1、对于一个自定义的对象,占用多大的空间呢?
@interface Person : NSObject
{
@public
int _age;
int _height;
}
@end
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
int _height;
};
16字节 = isa(8) + int(4) +int(4)
5.2、对于一个如下自定义的对象,占用多大的空间呢?
在64bit的环境下,一个Person对象和一个Student对象占用多少内存空间?
// Person
@interface Person : NSObject
{
@public
int _age;
}
@end
@implementation Person
@end
// Student
@interface Student : Person
{
@public
int _height;
}
@end
@implementation Student
@end
代码分析:
struct NSObject_IMPL {
Class isa; // 8个字节
};
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS; // 8个字节
int _age; // 4个字节
}; // 16个字节<内存对齐>
struct Student_IMPL {
struct Person_IMPL Person_IVARS; // 16个字节,空余四个
int _height; // 4个字节
}; // 16个字节<内存对齐>
6、对象的isa指针指向哪?
instance的isa指向class
class的isa指向meta-class
meta-class的isa指向基类meta-class
底层原理总结 — isa和superclass
7、OC的类信息都放在哪里?
成员变量的具体值存放在instance对象中
对象方法,协议,属性,成员变量信息放在class对象中
类方法信息存放在meta-class对象中
8、判断class
是否为meta-class
Class metaClass = object_getClass([Person class]);
Class class = [Person superclass];
NSLog(@"%d %d",class_isMetaClass(metaClass),class_isMetaClass(class));
结果:
1 0
9.1、Category
的原理是啥?
Category编译之后的底层结构是struct category_t
,里面存储着分类的对象方法,类方法,协议,属性信息。
在程序运行的时候,runtime
会将Category
的数据合并到类中<类对象和元类对象>
9.2、当我们调用Category
的方法是怎么调用的?
参考第一条问题答案。
调用对象方法:通过对象的isa找到类对象,找到类对象中的方法,调用
调用类方法:通过类对象的isa找到元类对象,扎到元类对象中的类方法,调用
9.3、当Category
中和类中存在相同方法的时候,最终调用的是哪一个?
调用的是Category中的方法
因为类方法列表已经放到整体方法列表的后面了。
所以调用相同方法的时候,会优先遍历到分类中的方法
9.4、当多个Category
中存在相同方法的时候,最终调用的是哪一个?
会调用后编译的分类中的方法
因为runtime将分类中的方法列表合并到类对象中的时候,是倒叙遍历的,所以后被编译的分类中的方法列表优先被加到类对象中。
那么分类的编译顺序在哪里查看呢?
9.5、Category
和Class Extension
有啥区别?
#import "Person.h"
@interface Person()
@property (nonatomic, copy) NSString *address;
@end
@implementation Person
- (void)run {
NSLog(@"Person");
}
@end
Class Extension
在编译的时候,他的数据已经包含在了Class
中了
Category
中的信息要等到runtime
的时候才会合并到Class
中