首页 > 解决方案 > 转换为协议时未调用协议扩展方法

问题描述

protocol StateManager : class {
    func predicate(filterTag: String?) -> NSPredicate?
}

extension StateManager {
    func predicate(filterTag: String?) -> NSPredicate?
    {
        print("StateManager.predicate(\(filterTag!))")
        return nil
    }
}

class StateMachine<T, S, E> : StateManager {
}

class A : StateManager {
    func predicate(filterTag: String?) -> NSPredicate?
    {
        print("concrete A.predicate(\(filterTag!))")
        return NSPredicate(value: true)
    }
}

class B : StateManager {
    func predicate(filterTag: String?) -> NSPredicate?
    {
        print("concrete B.predicate(\(filterTag!))")
        return NSPredicate(value: false)
    }
}

extension StateManager where Self : StateMachine<String, String, String> {
    //FIXME: Refactor to use an enum vs. String?
    func predicate(filterTag: String?) -> NSPredicate?
    {
        print("StateMachine<String, String, String>.predicate(\(filterTag!))")
        return NSPredicate(value: true)
    }
}

extension StateManager where Self : StateMachine<Int, Int, Int> {
    //FIXME: Refactor to use an enum vs. String?
    func predicate(filterTag: String?) -> NSPredicate?
    {
        print("StateMachine<Int, Int, Int>.predicate(\(filterTag!))")
        return NSPredicate(value: false)
    }
}

example("Call via concrete type") {
    let intState: StateMachine<Int, Int, Int> = StateMachine<Int, Int, Int>()
    let strState: StateMachine<String, String, String> = StateMachine<String, String, String>()
    let a: A = A()
    let b: B = B()

    intState.predicate(filterTag: "intState")
    strState.predicate(filterTag: "strState")
    a.predicate(filterTag: "A")
    b.predicate(filterTag: "B")
}

example("Call via protocol type") {
    let intState: StateMachine<Int, Int, Int> = StateMachine<Int, Int, Int>()
    let strState: StateMachine<String, String, String> = StateMachine<String, String, String>()
    let a: A = A()
    let b: B = B()

    let intProtocol = intState as StateManager
    let strProtocol = strState as StateManager
    intProtocol.predicate(filterTag: "intProtocol")
    strProtocol.predicate(filterTag: "strProtocol")

    let aProtocol = a as StateManager
    let bProtocol = b as StateManager
    aProtocol.predicate(filterTag: "aProtocol")
    bProtocol.predicate(filterTag: "bProtocol")
}

输出是

--- Call via concrete type example ---
StateMachine<Int, Int, Int>.predicate(intState)
StateMachine<String, String, String>.predicate(strState)
concrete A.predicate(A)
concrete B.predicate(B)

--- Call via protocol type example ---
StateManager.predicate(intProtocol)
StateManager.predicate(strProtocol)
concrete A.predicate(aProtocol)
concrete B.predicate(bProtocol)

我明白为什么 A & B 实例即使在强制转换为时也总是调用具体方法,但是如果我在实例上StateManager定义扩展方法,为什么结果会有所不同?是否会被强制转换为从而切断for &的最具体版本? StateManagerStateMachineSelfStateManagerpredicate()StateMachine<Int, Int, Int>StateMachine<String, String, String>

基本上我希望StateMachine<Int, Int, Int>&StateMachine<String, String, String>泛型类型有自己的实现,predicate()当我将任一泛型类型转换为 时StateManager,我希望predicate()泛型类型上执行(不是默认StateManager实现。结果应该与predicate()通过转换A&B类执行相同至StateManager

--- Call via protocol type example ---
(StateMachine<Int, Int, Int> as StateManager).predicate() 
-calls-> StateMachine<Int, Int, Int>.predicate(intState)

(StateMachine<String, String, String> as StateManager).predicate() 
-calls-> StateMachine<String, String, String>.predicate(strState)
concrete A.predicate(aProtocol)
concrete B.predicate(bProtocol)

有没有办法做到这一点,或者我不能为此使用协议扩展方法?

标签: swiftprotocols

解决方案


推荐阅读