我真的很喜欢 Sulthan 的回答(在 Anonymous class in swift 中) 它描述了构建一个符合协议(protocol)但其类隐藏在闭包内的对象。这对于构建单例非常有用,并且不会被 Recorder1、Recorder2 等类污染 namespace ......
但是,当我尝试用它做任何有用的事情时,我失败了,因为闭包不会关闭内部类中外部类的实例成员。
protocol EventListener {
func handleEvent(event: Int) -> ()
}
class Recorder {
static var events = [Int]() // static is forced
var listener: EventListener = {
class R : EventListener {
func handleEvent(event: Int) {
events.append(event)
print("Recorded: \(event)")
}
}//
return R()
}()
}// Recorder
class Distributor {
var listeners = [EventListener]()
func register(listener: EventListener){
listeners.append(listener)
}
func distribute(event: Int){
for listener in listeners {
listener.handleEvent(event)
}
}
}
var d = Distributor()
var r1 = Recorder()
var r2 = Recorder()
d.register(r1.listener)
d.register(r2.listener)
d.distribute(10)
print(Recorder.events) // [10, 10] Same event recorded twice.
上面的代码编译并运行。但我希望 Recorder 中的 events 成为实例成员,以便每个 Recorder 都有自己的记录。删除 static
会引发编译器错误:无法使用实例成员“事件”。
我尝试在 Recorder 中定义一个实例 func record(event)
供 handleEvent(event)
调用,但出现了相同的错误。
Marius 的回答(在 Instance member cannot be used on type | Closures 中)建议您在定义属性时无法访问实例成员,因此我稍后也尝试像这样计算监听器。
class Recorder {
var events = [Int]()
var listener: EventListener {
class R : EventListener {
func handleEvent(event: Int) {
events.append(event) // error: can't access events
print("Recorded: \(event)")
}
}
return R()
}
}// Recorder
但是编译器说它无法访问外部自身。
如果闭包无法访问外部 self ,那么它们看起来就非常无能为力。在 Java 中,您可以使用诸如 Recorder.self.events
之类的东西来获取外部 self。并且 Recorder.self.
可能仅在存在名称冲突时才需要(?)
Swift 是这样设计的还是我错过了什么?
你会如何编写它,以便Recorder
为Distributor
提供一个除了接收handleEvent消息之外什么都不做的对象?
非常感谢。
最佳答案
我不相信有办法在部分初始化的记录器中关闭事件。但是,您可以为记录器创建一个两阶段的初始化过程。第一阶段使用默认的空监听器创建 Recorder 对象。第二阶段创建一个适当的事件闭包并将其分配给监听器。
此实现没有 EventListener 协议(protocol)。我确信有一种简单的方法可以做到这一点,但对于嵌套类来说,这似乎有点矫枉过正。因此,Distributor 不是包含对象数组,而是包含闭包。我们让 Distributor 直接包含闭包数组。
除了对 initialize
的额外调用之外,您的 API 不会更改。
typealias EventListener = (Int) -> ()
class Distributor {
var listeners = [EventListener]()
func register(listener: EventListener){
listeners.append(listener)
}
func distribute(event: Int){
for listener in listeners {
listener(event)
}
}
}
class Recorder {
var events = [Int]()
var listener: EventListener = {
(event: Int) in
fatalError("Listener not initialized")
}
func initialize() {
listener = {
(event: Int) in
self.events.append(event)
print("Recorded: \(event)")
}
}
}
var d = Distributor()
// 1st stage of Recorder instantiation
var r1 = Recorder()
var r2 = Recorder()
// 2nd stage
// r1.listener can now have a closure that includes an init'ed events
r1.initialize()
r2.initialize()
d.register(r1.listener)
d.register(r2.listener)
d.distribute(10)
print(r1.events)
print(r2.events)
关于swift - 为什么闭包不能关闭实例成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35970401/