为什么闭包不能关闭实例成员
Why can't closures close over instance members
我非常喜欢 Sulthan 的回答(在 Anonymous class in swift 中)
它描述了构建一个符合协议但其 class 隐藏在闭包中的对象。这对于构建单例并且不会污染名称-space 与 class 类似 Recorder1、Recorder2...
非常有用
但是,当我尝试用它做任何有用的事情时,我失败了,因为闭包不会关闭内部 class.
内部的外部 class' 实例成员
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
会引发编译器错误:实例成员 'events' 无法使用 .
我尝试在 Recorder 中定义一个实例 func record(event)
供 handleEvent(event)
调用,但我得到了同样的错误。
Marius 的回答(在 中)建议您不能在定义属性时访问实例成员,所以我稍后也尝试像这样计算侦听器。
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
但是编译器说它不能访问外部自身。
如果闭包无法访问外在自我,则它们似乎非常无能为力。在 Java 中,你可以通过 Recorder.self.events
之类的东西到达外在的自我。并且 Recorder.self.
可能仅在存在名称冲突时才需要(?)
Swift 是这样设计的还是我错过了什么?
你会怎么写它 Recorder
给 Distributor
一个除了接收 handleEvent 消息什么也做不了的对象?
非常感谢。
我认为没有办法关闭部分初始化的记录器中的事件。但是,您可以为 Recorder 创建一个两阶段的初始化过程。第一阶段使用默认的空侦听器创建 Recorder 对象。第二阶段创建一个适当的事件闭包并将其分配给侦听器。
此实现没有 EventListener 协议。我确信有一种简单的方法可以做到这一点,但对于嵌套 类 来说,这似乎有点过分了。所以 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)
使用 Price Ringo 的 2 阶段初始化,并让 Recorder 将 self
传递到内部 class,我得到了我正在寻找的 class 隐藏。它比我希望的要冗长一点,但具有使 Recorder 实例成员的生命周期清晰的优点。例如,它避免了围绕 events
的复制与引用混淆。 self
还可以轻松地以另一种方式传递数据:adjustment
。
Price Ringo 的解决方案更优雅,更适合这个特定问题。此解决方案更通用,适用于任何现有协议。总的来说,我正在尝试将面向协议的模式合并到我的代码中。此解决方案创建的对象除了它们遵循的协议外没有其他类型。
protocol EventListener {
func handleEvent(event: Int) -> ()
}
class Recorder {
var events = [Int]() // example of data out
let adjustment: Int // example of data in
var listener: EventListener = {
class __: EventListener {
func handleEvent(event: Int) { }
}
return __()
}()
init(adjustment: Int){
self.adjustment = adjustment
initializeListener()
}
private func initializeListener() {
listener = {
class __: EventListener {
unowned var recorder: Recorder
init(recorder: Recorder){
self.recorder = recorder
}
func handleEvent(event: Int) {
let adjustedEvent =
recorder.adjustment * event
recorder.events.append(adjustedEvent)
// print("Recorded: \(adjustedEvent)")
}
}
return __(recorder: self)
}()
}
}// Recorder
class Distributor {
var listeners = [EventListener]()
func addListener(listener: EventListener){
listeners.append(listener)
}
func distributeEvent(event: Int){
for listener in listeners {
listener.handleEvent(event)
}
}
}
var d = Distributor()
var r1 = Recorder(adjustment: 2)
var r2 = Recorder(adjustment: 3)
d.addListener(r1.listener)
d.addListener(r2.listener)
d.distributeEvent(10)
print(r1.events) // [20]
print(r2.events) // [30]
如果你还在阅读,我有一个问题。我已将实例成员 __>recorder
设置为无主以避免保留。我还需要让 Recorder>listener
无主吗?
我非常喜欢 Sulthan 的回答(在 Anonymous class in swift 中) 它描述了构建一个符合协议但其 class 隐藏在闭包中的对象。这对于构建单例并且不会污染名称-space 与 class 类似 Recorder1、Recorder2...
非常有用但是,当我尝试用它做任何有用的事情时,我失败了,因为闭包不会关闭内部 class.
内部的外部 class' 实例成员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
会引发编译器错误:实例成员 'events' 无法使用 .
我尝试在 Recorder 中定义一个实例 func record(event)
供 handleEvent(event)
调用,但我得到了同样的错误。
Marius 的回答(在
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
但是编译器说它不能访问外部自身。
如果闭包无法访问外在自我,则它们似乎非常无能为力。在 Java 中,你可以通过 Recorder.self.events
之类的东西到达外在的自我。并且 Recorder.self.
可能仅在存在名称冲突时才需要(?)
Swift 是这样设计的还是我错过了什么?
你会怎么写它 Recorder
给 Distributor
一个除了接收 handleEvent 消息什么也做不了的对象?
非常感谢。
我认为没有办法关闭部分初始化的记录器中的事件。但是,您可以为 Recorder 创建一个两阶段的初始化过程。第一阶段使用默认的空侦听器创建 Recorder 对象。第二阶段创建一个适当的事件闭包并将其分配给侦听器。
此实现没有 EventListener 协议。我确信有一种简单的方法可以做到这一点,但对于嵌套 类 来说,这似乎有点过分了。所以 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)
使用 Price Ringo 的 2 阶段初始化,并让 Recorder 将 self
传递到内部 class,我得到了我正在寻找的 class 隐藏。它比我希望的要冗长一点,但具有使 Recorder 实例成员的生命周期清晰的优点。例如,它避免了围绕 events
的复制与引用混淆。 self
还可以轻松地以另一种方式传递数据:adjustment
。
Price Ringo 的解决方案更优雅,更适合这个特定问题。此解决方案更通用,适用于任何现有协议。总的来说,我正在尝试将面向协议的模式合并到我的代码中。此解决方案创建的对象除了它们遵循的协议外没有其他类型。
protocol EventListener {
func handleEvent(event: Int) -> ()
}
class Recorder {
var events = [Int]() // example of data out
let adjustment: Int // example of data in
var listener: EventListener = {
class __: EventListener {
func handleEvent(event: Int) { }
}
return __()
}()
init(adjustment: Int){
self.adjustment = adjustment
initializeListener()
}
private func initializeListener() {
listener = {
class __: EventListener {
unowned var recorder: Recorder
init(recorder: Recorder){
self.recorder = recorder
}
func handleEvent(event: Int) {
let adjustedEvent =
recorder.adjustment * event
recorder.events.append(adjustedEvent)
// print("Recorded: \(adjustedEvent)")
}
}
return __(recorder: self)
}()
}
}// Recorder
class Distributor {
var listeners = [EventListener]()
func addListener(listener: EventListener){
listeners.append(listener)
}
func distributeEvent(event: Int){
for listener in listeners {
listener.handleEvent(event)
}
}
}
var d = Distributor()
var r1 = Recorder(adjustment: 2)
var r2 = Recorder(adjustment: 3)
d.addListener(r1.listener)
d.addListener(r2.listener)
d.distributeEvent(10)
print(r1.events) // [20]
print(r2.events) // [30]
如果你还在阅读,我有一个问题。我已将实例成员 __>recorder
设置为无主以避免保留。我还需要让 Recorder>listener
无主吗?