面试题答案
一键面试1. Objective - C的元类体系
在Objective - C中,每个类(Class
)都有一个关联的元类(meta - class
)。元类用于存储类方法。类对象的isa
指针指向其元类,而元类的isa
指针指向根元类。根元类的isa
指针指向自身。根类(如NSObject
)的元类的父类是根类本身,其他元类的父类是其对应类的父类的元类。这种体系结构形成了一个复杂的继承层次,使得类方法也能像实例方法一样遵循继承规则。
2. self与super在元类体系下的消息传递和方法调度
- self:当使用
self
发送消息时,运行时系统首先会在self
的类(如果是类方法,就是元类)的方法列表中查找方法实现。如果找不到,就沿着继承链(元类的继承链)向上查找,直到找到方法实现或者到达根元类。 - super:
super
并不是一个指针,而是一个编译器指示符。当使用super
发送消息时,编译器会改变消息查找的起始点。对于类方法,会从当前类的元类的父类的方法列表开始查找方法实现,然后沿着继承链向上查找,这与self
从当前类(元类)开始查找不同。
3. 类方法中self和super消息发送的具体流程
代码示例
#import <Foundation/Foundation.h>
@interface ParentClass : NSObject
+ (void)classMethod;
@end
@implementation ParentClass
+ (void)classMethod {
NSLog(@"ParentClass class method");
}
@end
@interface ChildClass : ParentClass
+ (void)classMethod;
@end
@implementation ChildClass
+ (void)classMethod {
NSLog(@"ChildClass class method before self");
[self classMethod];
NSLog(@"ChildClass class method before super");
[super classMethod];
NSLog(@"ChildClass class method after super");
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[ChildClass classMethod];
}
return 0;
}
流程分析
[self classMethod]
:在ChildClass
的类方法classMethod
中,当执行[self classMethod]
时,运行时系统首先在ChildClass
的元类的方法列表中查找classMethod
。因为ChildClass
元类中有该方法,所以会调用ChildClass
的classMethod
,形成递归调用。为了打破递归,ChildClass
的classMethod
实现中应该避免这种直接递归,实际应用中会有不同的业务逻辑。这里递归调用会一直执行ChildClass class method before self
这行日志输出,直到栈溢出。在修正代码避免递归后,会执行到[super classMethod]
。[super classMethod]
:当执行[super classMethod]
时,编译器会让运行时系统从ChildClass
元类的父类(也就是ParentClass
的元类)的方法列表中查找classMethod
。找到后执行ParentClass
的classMethod
,输出ParentClass class method
。执行完ParentClass
的classMethod
后,继续执行ChildClass
类方法中[super classMethod]
之后的代码,输出ChildClass class method after super
。
4. 这种机制对Objective - C运行时特性的重要影响
- 动态绑定:通过元类体系和
self
、super
的消息传递机制,Objective - C实现了动态绑定。在运行时才确定方法的实际调用,这使得程序更加灵活,比如可以在运行时替换类的实现等。 - 继承与多态:元类体系和消息传递机制保证了类方法也能像实例方法一样遵循继承和多态规则。子类可以重写父类的类方法,并且通过
super
调用父类的类方法实现,增强了代码的复用性和扩展性。 - 运行时的灵活性:这种机制使得Objective - C在运行时可以进行许多高级操作,如方法交换(
method swizzling
)。可以在运行时动态改变类的方法实现,无论是实例方法还是类方法,这在很多框架和库的实现中都有广泛应用,比如AOP(面向切面编程)的实现。