调用Swift协议初始化程序

问题描述 投票:0回答:1

Swift 5,在XCode 11.2.1上。我已经永远用Java编程了,在这一点上我只是对Swift有所了解,所以我的一些理解被Java习惯用语所染。

假设我们提供了一个协议,或者可能是一个伪抽象类,可以在一个单独的模块中实现。然后,程序员将对类的引用传递回第一个模块中的代码,从而实例化其类。现在,在Java中这很困难,因为您无法保证子类将定义哪些初始化器/静态方法。但是,在Swift中,您可以。这很整洁。除了,我还没有找到使用它们的方法。我expect的意思是您可能拥有类似的代码,例如

protocol FooP {
  init(s: String)
}

func instantiate(clazz: FooP.Type) -> FooP {
  return clazz.init(s: "qwerty")
}

... OOOOORRRR确实可以正常工作,正如我希望的那样。我认为在测试中,我只是未能找到CLASS / .Type / .self的正确组合来提示我成功的可能性。

由于搜寻了30-60分钟,尽管我没有找到关于此可能性的任何其他信息,我会回答我自己的问题。

ios swift types static swift-protocols
1个回答
0
投票

事实证明,即使所涉及的类(而不是其实例化)被强制转换为其协议,也可以使用协议提供的静态方法。您甚至可以使用泛型来使示例instantiate方法更方便地具有您提供的返回类型,尽管这会导致如下所示的其他问题。这是一堆代码,展示了您可以做和不能做的事情:

public protocol ProtocolTest {
    init(s: String)

    static func factory(s: String) -> Self
}

public class Foo : ProtocolTest, CustomStringConvertible {
    public let s: String

    public required init(s: String) {
        self.s = s
    }

    public static func factory(s: String) -> Self {
        return Self(s: s)
    }

    public var description: String { return "{\(Self.self)|s:\"\(s)\"}" }
}

public class Bar : Foo {
}

public func instantiateGeneric<T : ProtocolTest>(clazz: T.Type) -> T {
    return clazz.init(s: "qwertyGeneric")
}

public func instantiateNongeneric(clazz: ProtocolTest.Type) -> ProtocolTest {
    return clazz.init(s: "qwertyNongeneric")
}

public func run() {
    let ptts: [ProtocolTest.Type] = [Foo.self, Bar.self]

    // Success
    let aInit : Bar = Bar.init(s: "qwertyInit")
    // Success
    let aGeneric : Bar = instantiateGeneric(clazz: Bar.self)
    // Compile error: Cannot convert value of type 'ProtocolTest' to specified type 'Bar'
    let aNongeneric : Bar = instantiateNongeneric(clazz: Bar.self)

    for ptt in ptts {
        // Success
        let bInit : ProtocolTest = ptt.init(s: "qwertyInit")
        // Compile error: Protocol type 'ProtocolTest' cannot conform to 'ProtocolTest' because only concrete types can conform to protocols
        let bGeneric1 : ProtocolTest = instantiateGeneric(clazz: ptt)
        // Compile error: Cannot invoke 'instantiateGeneric' with an argument list of type '(clazz: ProtocolTest.Type)'
        let bGeneric2 = instantiateGeneric(clazz: ptt)
        // Success
        let bNongeneric : ProtocolTest = instantiateNongeneric(clazz: ptt)
        // This works too, btw:
        let bFactory : ProtocolTest = ptt.factory(s: "qwertyFactory")
    }
}

我不确定循环中instantiateGeneric到底发生了什么。似乎是合理的代码行。让我知道您是否有解释。也许关于<T : ProtocolTest>ProtocolTest在技术上不符合ProtocolTest,或者也许它必须是严格的子类?不确定。能够在两种用途中使用相同的方法会很好,但是我已经对自己可以做的事情感到非常满意。这个发现可能足以让我真正喜欢Swift,哈哈。

© www.soinside.com 2019 - 2024. All rights reserved.