如何在Swift中使用带有关联类型的协议关闭时使用Void类型

时间:2019-06-05 09:38:31

标签: swift closures swift-protocols

我有一个小问题,我找不到一种优雅的方式来使用带有关联类型的闭包作为协议中的Void。

假设我具有以下协议:

protocol MyProtocol {

  associatedtype OutputDataType
  associatedtype InputDataType

  var isCompleted: ( (InputDataType) -> OutputDataType)? { get set }
}

现在我有一个符合此协议的类,它的闭包内部具有Void类型,如下所示:

class MyClass: MyProtocol {
  var isCompleted: ( () -> Void )? // Error: Type 'MyClass' does not conform to protocol 'MyProtocol'
}

所以我尝试了这个:

var isCompleted: ( (Void) -> Void )? // warning: When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?

并以这种“怪异”语法结束:

var isCompleted: ( (()) -> Void )?

或这个冗长的内容:

typealias InputDataType = Void
var isCompleted: ( (InputDataType) -> Void )?

但是现在当我想在另一个类中分配此闭包时,我需要在参数中明确使用“ _”:

myClass.isCompleted = { _ in
// other code
}

不可能使用这样的东西:

myClass.isCompleted = {
// other code
}

那么您是否知道像我引用并期望的示例那样可以获得更优雅的东西?

1 个答案:

答案 0 :(得分:1)

由于已通过协议声明了isCompleted的必要性,因此您将不得不在MyClass中实现它,不幸的是使用了“怪异”语法。

但是,为了更好地使用它,您可以在InputDataType == Void时为协议添加扩展名,以方便访问isCompleted,而不必显式传递Void ...像这样:

extension MyProtocol where InputDataType == Void {
    var isCompleted: (() -> OutputDataType)? {
        get {
            guard let isCompleted = self.isCompleted else { return nil }
            return { return isCompleted(()) }
        }
        set {
            if let newValue = newValue {
                self.isCompleted = { _ in return newValue() }
            } else {
                self.isCompleted = nil
            }
        }
    }
}

然后,您可以通过方便的方式在类上使用该方法,从而为您提供了所要查找的最后一个代码示例:

var myClass = MyClass()
myClass.isCompleted = {
    print("Hello World!")
}
myClass.isCompleted?()