2

我对 Obj-C 消息有一些疑问。

(1) 这是我的主要问题:如何确保一个类在混合或调用它之前具有其超类的实现?

如果我想使用目标类未实现但其超类实现的方法进行方法调配,如何确保该类在方法调配之前具有其超类的实现?

我知道当一条消息发送到一个没有实现它的对象时,Obj-C 运行时将首先查找它的继承层次结构以从它的超类中找到实现。如果有,Obj-C 会将其缓存在不同的调度表中并调用它。

我可以使用这个缓存的实现进行方法调配吗?如果可以,如何确保在方法调配或向该对象发送任何消息之前有一个缓存的实现?如果没有,如何向这个类添加一个真正的实现,它只会super在方法调整之前调用 's 的实现?

例如,有这样的类层次结构:

@interface A : NSObject
- (void) helloWorld;
@end

@interface B : A
@end

@interface C : B
@end

@interface D : C
@end

@interface E : D
@end

和这样的实现:

@implemenation A
- (void) helloWorld{
    NSLog(@"hello world from class A");
}
@end

@implemenation B
// did not override -helloWorld
@end

@implemenation C
- (void) helloWorld{
    [super helloWorld];
    NSLog(@"hello world from class C");
}
@end

@implemenation D
// did not override -helloWorld
@end

@implemenation E
// did not override -helloWorld
@end

我只想在运行时-helloWorld与 Class完全交换(而不是添加)实现。D如果这样的 swizzled 方法,这个技巧将在原始实现中添加一个额外的任务:

@implemenation D (AdditionalWorkForHelloWorld)
- (void) additionalWorkForHelloWorld{
    [self additionalWorkForHelloWorld];
    NSLog(@"hello every one!");
}
@end

因此,当我向 Class或 Class-helloWorld的实例发送消息时,控制台将打印以下消息:DE

-> hello world from class A
-> hello world from class C
-> hello every one!

有一天,在类D实现-helloWorld如下之后:

@implemenation D
- (void) helloWorld{
    [super helloWorld];
    NSLog(@"hello world from class D");
}
@end

并向 Class或 Class-helloWorld的实例发送消息,控制台将打印以下消息:DE

-> hello world from class A
-> hello world from class C
-> hello world from class D
-> hello every one!

这种方法交换将确保无论类D实现-helloWorld与否都会调用附加任务。

问了一个关于如何使 C 函数调用对象的super实现的问题,这似乎并不容易。Obj-C 是如何实现这种缓存机制来将消息转发到super's implementation 的?

(2) Obj-C 如何处理super关键字?在哪里super

在 Obj-C 消息中,前两个参数是隐藏的:self_cmd. 您可以在 Obj-C 实现中使用它们。但在哪里super

a 是否super等于self'isa指针?Obj-C 如何处理super关键字?

每个 Obj-C 消息都将转换为objc_msgSend()or objc_msgSend_stret()。那么发送到的每条消息super都会转换为objc_msgSendSuper()andobjc_msgSendSuper_stret()吗?

在前面提到的示例中,当我向-helloWorldClass 发送消息并且EClass不响应时,Obj-C 会将消息发送到 Class的实现。在 Class的 implementation 中,它调用了它的 implementation,但 Class没有实现它,所以将它转发给 Class 。DECCsuperBA

在这种情况下,superClassC应该是 Class B,所以它实际上调用了 ClassB的缓存实现,不是吗?我可以调整 ClassB的缓存实现吗?

4

1 回答 1

3

一条消息super发送到self。但是,实现的查找从不同的地方开始。当您发送消息self时,Objective-C 运行时(objc_msgSend()等)首先在selfisa指针指向的类中查找。如果在那里没有找到实现,则搜索移动到超类,依此类推。

当您发送消息super时,搜索从代码包含调用的类的超类开始super。是的,消息 tosuper转换为调用objc_msgSendSuper()或其变体之一。编译器构造一个objc_super结构,其中包含self当前正在编译的类的超类。(注意:这不同[self superclass]。该表达式是动态的,取决于 的实际类self。消息指向的超类super不是动态的,不取决于 的实际类self。)

无论如何,objc_msgSendSuper()使用结构中引用的超类objc_super来控制它开始搜索实现的位置,但在其他方面的行为类似于objc_msgSend(). 就是这样。就是super这样:它开始沿着类链进一步搜索实现。

至于如何实现你的 swizzling 目标……我想你想先尝试添加一个调用super. 如果失败(因为该类已经有这样的方法),那么在调用原始方法的不同实现中进行调配。

所以,像:

@implemenation D (AdditionalWorkForHelloWorld)
- (void) addedHelloWorldIfNotPresent{
    [super helloWorld];
    NSLog(@"hello every one!");
}
- (void) additionalWorkForHelloWorld{
    [self additionalWorkForHelloWorld];
    NSLog(@"hello every one!");
}
@end

然后尝试添加-addedHelloWorldIfNotPresentusing的实现class_addMethod()+[NSObject instanceMethodForSelector:]使用with获取实现@selector(addedHelloWorldIfNotPresent)。如果添加方法失败,则改用-additionalWorkForHelloWorld现有的-helloWorld.

于 2013-12-02T17:31:48.590 回答