检查子类是否覆盖方法

时间:2015-02-26 07:57:15

标签: ios objective-c inheritance

是否有可能检查子类是否实现了一个存在于其直接超类或其超类的某些超类中的方法等?

E.g。我子类UIView,为我的应用程序创建自定义通用视图,然后我将此自定义视图子类化。现在我的一些子类会覆盖UIView中的某些方法,而有些则不会。我只想调用此方法,如果它实际被覆盖,我不希望调用默认的UIView方法。

有没有办法检查这个,即使用类似于respondsToSelector:的方法?

修改 这个问题与Objective-C detect if class overrides inherited method中提出的问题不同,因为我真的不知道或者不想关心哪个超类最初实现该方法。

7 个答案:

答案 0 :(得分:9)

基于Mert Buran的answer

您可以创建一个简单的方法来检查给定对象是否覆盖给定的选择器(方法):

-(BOOL)checkIfObject:(id)object overridesSelector:(SEL)selector {

    Class objSuperClass = [object superclass];
    BOOL isMethodOverridden = NO;

    while (objSuperClass != Nil) {

        isMethodOverridden = [object methodForSelector: selector] !=
        [objSuperClass instanceMethodForSelector: selector];

        if (isMethodOverridden) {
            break;
        }

        objSuperClass = [objSuperClass superclass];
    }

    return isMethodOverridden;
}

可以这样调用:

[self checkIfObject:someObject overridesSelector:@selector(someSelector)];

答案 1 :(得分:2)

不幸的是,没有相当于respondsToSelector:的人可以完成这项工作。您可能知道,只要类本身或其任何超类实现此方法,respondsToSelector:就会以返回YES的方式工作。

但是为什么不把这个方法的空实现放到你的自定义子类中,这样你就可以确保调用它没有任何效果并且不会在超类中调用相同的方法。你有没有想过这个?

<强>更新 虽然没有相当于respondsToSelector:的方法,但您可能需要查看 Objective-C运行时。它是一个库,允许您在运行时检查类的特征(有点类似于Java反射)。查看参考here

答案 2 :(得分:1)

不是最佳解决方案,但您可以将一个布尔成员保留到您的UIView子类(让我们称之为UIViewSub,指示该类是否实现了所需的行为,并在使用该方法之前检查该布尔值。

您的子类(继承UIViewSub的子类)将在其构造中相应地设置/取消设置此成员(即,它是否通过实现覆盖它)

答案 3 :(得分:1)

扩展ZeMoon的答案,我发现没有足够的逻辑来满足所有情况。我需要添加一个检查以确保循环中下一个超类的实例完全实现指定的选择器。 UIView的子类就是一个例子。

while (objSuperClass != Nil) {
    isMethodOverridden = ([objSuperClass instancesRespondToSelector:selector]) && 
                         ([object methodForSelector:selector] !=
                          [objSuperClass instanceMethodForSelector:selector]);

    if (isMethodOverridden) {

    }
}

答案 4 :(得分:1)

您可能会问Why?! ‍♂️…,但是如果有一天晚上您发现自己正在寻找如何在Swift 4中做到这一点–就是这样:

import Foundation

extension NSObject
{
    func overrides(_ selector: Selector) -> Bool {
        var currentClass: AnyClass = type(of: self)
        let method: Method? = class_getInstanceMethod(currentClass, selector)

        while let superClass: AnyClass = class_getSuperclass(currentClass) {
            // Make sure we only check against non-nil returned instance methods.
            if class_getInstanceMethod(superClass, selector).map({ $0 != method}) ?? false { return true }
            currentClass = superClass
        }

        return false
    }
}

class Foo: NSObject { @objc func mtd() {} }
class Bar: Foo {}
class Baz: Bar { override func mtd() {} }
class Qux: Bar {}
class Fen: Baz {}

Foo().overrides(#selector(Foo.mtd)) // false
Bar().overrides(#selector(Bar.mtd)) // false
Baz().overrides(#selector(Baz.mtd)) // true
Qux().overrides(#selector(Qux.mtd)) // false
Fen().overrides(#selector(Fen.mtd)) // true

答案 5 :(得分:0)

使用运行时,您想要使用该功能 方法

* class_copyMethodList ( Class cls, unsigned int *outCount );

这将为您提供一个可供使用的列表。

答案 6 :(得分:0)

适用于Swift 4.0(并添加了可选的baseClass BELOW,该算法用于查找替代):

extension NSObject {

    func checkIf(overrides selector: Selector, baseClass: AnyClass? = nil) -> Bool {
        guard var objSuperClass = self.superclass else { return false }

        var isOverridden = false

        while objSuperClass != nil {
            isOverridden = object.method(for: selector) != objSuperClass?.instanceMethod(for: selector)
            if isOverridden {
                break
            }
            objSuperClass = objSuperClass?.superclass()
            if objSuperClass == baseClass {
                break
            }
        }

        return isOverridden
    }
}