【发布时间】:2015-04-02 15:42:24
【问题描述】:
假设以下类层次结构。 A 类已公开声明:
@interface A : NSObject
+ (A)createInstance;
- (void)a;
@end
_B 类是 A 的私有子类:
@interface _B : A
- (void)a;
- (void)b;
@end
假定类A 的对象只能使用工厂方法createInstance 创建,该方法创建并返回_B 的实例。
我想在每个实例的基础上增强A 实例的功能。所以我决定做一些 ISA swizzling 来实现:
@interface ExtA : A
- (void)a;
@end
@implementation ExtA
- (void)a
{
NSLog("ExtA_a");
[super a];
}
@end
我在 NSObject 类别上使用以下方法进行 ISA swizzling(此处显示的幼稚实现):
- (void)changeToSubclass:(Class)cls prefix:(NSString*)prefix suffix:(NSString*)suffix
{
NSString* className = [NSString stringWithFormat:@"%@%@%@", prefix ? prefix : @"", NSStringFromClass(object_getClass(self)), suffix ? suffix : @""];
if([className isEqualToString:NSStringFromClass(object_getClass(self))])
{
className = [NSString stringWithFormat:@"%@(%@)", NSStringFromClass(object_getClass(self)), NSStringFromClass(cls)];
}
Class newSubclass = objc_getClass(className.UTF8String);
if(newSubclass == nil)
{
newSubclass = objc_allocateClassPair(object_getClass(self), className.UTF8String, 0);
objc_registerClassPair(newSubclass);
unsigned int listCount = 0;
Method *list = class_copyMethodList(cls, &listCount);
for(int i = 0; i < listCount; i++)
{
class_addMethod(newSubclass, method_getName(list[i]), method_getImplementation(list[i]), method_getTypeEncoding(list[i]));
}
free(list);
listCount = 0;
list = class_copyMethodList(objc_getMetaClass(class_getName(cls)), &listCount);
for(int i = 0; i < listCount; i++)
{
class_addMethod(objc_getMetaClass(class_getName(newSubclass)), method_getName(list[i]), method_getImplementation(list[i]), method_getTypeEncoding(list[i]));
}
free(list);
}
object_setClass(self, newSubclass);
}
一切看似正常,但我注意到[super a]; 的行为与预期不符,如果运行时中的超类实际上是_B,则实际上调用了-[A a] 的实现。
用以下代码替换对super 的调用是可行的,但很难看,并且需要开发人员的知识和工作:
struct objc_super superInfo = {
self,
[self superclass]
};
objc_msgSendSuper(&superInfo, @selector(a));
编译器在调用super 时会发出什么以及更改此发出的代码的任何方法?
【问题讨论】:
标签: objective-c superclass objective-c-runtime swizzling isa-swizzling