强键入Dictionary或NSDictionary以根据协议具有键和值



这是我的协议:

@objc public protocol EventListenerOptions {
@objc optional var capture: Bool { get set }
}

我有这个方法签名:

func addEventListener(
_ type: NSString,
_ callback: ((_ event: UIEvent) -> Void)?,
_ options: EventListenerOptions?
)

我该如何调用它?我尝试过使用静态声明的字典,但它不接受它。建议的插入as! EventListenerOptions的修复程序会产生编译器警告(在任何情况下都会在运行时崩溃(。

view.addEventListener(
"tap",
{(event: UIEvent) -> Void in
print("Got a tap event.")
},
["capture": true] // Error: Argument type '[String : Bool]' does not conform to expected type 'EventListenerOptions'
)

需求:我想将协议公开给Obj-C,所以我想要的是在Swift中获得类型安全的方法,同时处理在Obj-C中容易构建的对象(所以据我所知,我不能使用structs(。我希望我能通过一个NSDictionary广播的as EventListenerOptions,但它不接受。

与某些语言(如TypeScript(不同,Swift具有标称类型,而不是结构。这意味着,即使对象具有您想要的形状,除非其类明确采用协议,否则您无法将其传入

protocol EventListenerOptions {
var capture: Bool { get set }
}
class AnEventListenerOptionsType: EventListenerOptions {
var capture: Bool
}
class NotAnEventListenerOptionsType {
var capture: Bool
}

字典["capture": true]的类型不是符合EventListenerOptions的类:它是标准库类型Dictionary<String, Bool>。这种类型不仅没有采用协议,甚至没有相关的属性:必须通过dict["capture"]而不是dict.capture访问它。这是一个重要的区别:前者调用subscript(_:)访问器,而后者访问capture属性。(如果你来自TypeScript,正如@Alexander所建议的,你可能已经习惯了这些等价物,但在Swift中却不是。(

据我所知,Swift没有JS、C#、Kotlin等中的匿名对象文字。

TL;DR:解决方案是创建一个符合EventListenerOptions的类。

尝试添加

class Listener: EventListenerOptions { 
var capture: Bool = true
}
...
let listener = Listener()
listener.capture = true
view.addEventListener(
"tap",
{(event: UIEvent) -> Void in
print("Got a tap event.")
},
listener
)

最新更新