这是我的解决方案,结合以上的想法,修复了一些错误,并使其具有可扩展性。你可以直接使用它来监视某个类及其子类的superview变化,这应该是即插即用的。
用C语言编写以便易于理解和快速。你可以将其修改为NSObject的一些漂亮分类。
示例用法:
add_superview_kvo(UILabel.class)
那么您需要像正常使用一样向实例中添加自己的观察者。"Original Answer" 翻译成 "最初的回答"。
typedef struct {
Class target;
SEL cmd;
Method method;
IMP imp;
} override_t;
static override_t
_override_init(Class target, SEL sel) {
BOOL instance = YES;
override_t o = {
.target = target,
.cmd = sel,
.method = instance ? class_getInstanceMethod(target,sel) : class_getClassMethod(target,sel),
.imp = method_getImplementation(o.method)
};
return o;
};
static void
_override_patch(override_t o, id _Nonnull block) {
IMP imp = imp_implementationWithBlock(block);
if (!class_addMethod(o.target, o.cmd, imp, method_getTypeEncoding(o.method))){
method_setImplementation(o.method,imp);
}
}
void
add_superview_kvo(Class target)
{
NSString *keyPath = @"superview";
override_t override = _override_init(target,@selector(willMoveToSuperview:));
_override_patch(override,^void(id _self, UIView *superview) {
[_self willChangeValueForKey:keyPath];
((void(*)(id,SEL,id))override.imp)(_self, override.cmd, superview);
});
override = _override_init(target,@selector(didMoveToSuperview));
_override_patch(override,^void(id _self) {
((void(*)(id,SEL))override.imp)(_self, override.cmd);
[_self didChangeValueForKey:keyPath];
});
}
KVO自动通知仅支持返回void的-set<Key>:方法。对于-[WebView _setSuperview:]的调用将不会进行自动通知。
我很想找到更好的方法来解决这个问题,但是我还没有找到。 :-/ - nomothetis