面试题答案
一键面试类对象、元类对象概念及与类定义和声明的关系
- 类对象
- 概念:在Objective - C中,每个类在运行时都是一个
Class
类型的对象,称为类对象。它包含了类的相关信息,如类名、超类、实例变量布局、方法列表等。类对象用于创建该类的实例(即对象)。 - 与类定义和声明关系:类的声明(
@interface
)和定义(@implementation
)定义了类的结构和行为。编译器根据这些声明和定义,在运行时创建对应的类对象。例如,当我们声明一个Person
类:
- 概念:在Objective - C中,每个类在运行时都是一个
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (void)sayHello;
@end
@implementation Person
- (void)sayHello {
NSLog(@"Hello, my name is %@", self.name);
}
@end
运行时就会创建一个代表Person
类的类对象,它包含了name
属性和sayHello
方法等相关信息。
2. 元类对象
- 概念:元类对象是存储类方法的地方。每个类都有一个对应的元类对象。元类对象也是
Class
类型,它的超类是其类对象的超类的元类对象(根类的元类对象的超类是根类的类对象)。 - 与类定义和声明关系:类方法在类的声明和定义中定义,例如:
@interface Person : NSObject
+ (instancetype)personWithName:(NSString *)name;
@end
@implementation Person
+ (instancetype)personWithName:(NSString *)name {
Person *p = [[self alloc] init];
p.name = name;
return p;
}
@end
这些类方法存储在Person
类对应的元类对象中。
向类发送类方法消息时的底层消息传递机制
- 当向一个类发送类方法消息时,首先会在该类对应的元类对象的方法列表中查找方法的实现。例如,对于
[Person personWithName:@"John"]
,系统会到Person
类的元类对象的方法列表中找personWithName:
方法。 - 如果在元类对象的方法列表中没有找到,就会沿着元类对象的继承体系向上查找,即查找元类对象的超类(通常是其超类的元类对象)的方法列表,直到找到方法实现或者到达根类的元类对象且仍未找到(此时会走消息转发流程)。
运行时动态修改类的定义(添加新的实例方法)及影响
- 操作方法:可以使用Objective - C运行时库(
<objc/runtime.h>
)来动态添加实例方法。例如,假设有一个已经定义的Person
类,要动态添加一个新的实例方法run
:
#import <objc/runtime.h>
// 定义新方法的实现
void runMethod(id self, SEL _cmd) {
NSLog(@"%@ is running", self);
}
// 在运行时添加新方法
BOOL addMethod() {
Class personClass = object_getClass([Person class]);
return class_addMethod(personClass, @selector(run), (IMP)runMethod, "v@:");
}
- 对类结构的影响:运行时动态添加实例方法会修改类对象的方法列表,在类对象的方法列表中增加新的方法记录。
- 对现有对象的影响:现有对象可以立即调用新添加的方法,因为对象在接收消息时是根据类对象的方法列表来查找方法实现的。一旦类对象的方法列表更新,所有该类及其子类的对象都可以响应新添加的方法。