我一直在尝试在 Swift 中做一些我认为应该相对简单的事情——将闭包作为属性存储在结构中,这样它就可以通过使用结构的另一个属性来过滤数组。但是我遇到了一个障碍——我不能在结构初始化器中添加闭包,因为它想要引用的变量不存在,我不能使它成为一个惰性变量作为协议(protocol)的一部分(不确定如果这仍然有效),并且在初始化结构后我无法分配它,因为它将捕获我从中进行分配的对象的上下文,并尝试将其用于本地属性。一个简化的场景如下:
struct EventSpec {
var dateRange: DateInterval
var filterClosure: ((Date) -> Bool)?
init( dateRange: DateInterval) {
self.dateRange = dateRange
}
func provideMatchingEvents(for events: [Event] {
return events.filters{filterClosure($0.date)}
}
struct Event {
name: String
date: Date
}
理想情况下会像这样初始化
eventSpec = EventSpec(dateRange: aDateRamge, filterClosure: { self.dateRange.contains(date) 中的日期}
但这不起作用,因为此时没有 self.dateRange。
尝试在之后添加闭包,无论是直接添加还是通过“构建器”函数都不起作用,因为它捕获了它所涉及的位置的“ self ”,而不是访问 EventSpec 的 dateRange 属性。
我确信这应该是一个常见的模式,我遗漏了一些明显的东西,但只能找到引用(很多)将闭包添加为不引用其他属性的变量。
(我意识到,如果我在结构中对闭包进行硬编码,我可以通过标准捕获列表访问局部变量,但这消除了在运行时定义过滤器的能力)。
有人有什么想法吗?
最佳答案
闭包内代码的范围是它写入的对象。而不是它被传递到的对象。
所以在...
EventSpec(dateRange: aDateRamge) { date in
self.dateRange.contains(date)
}
self
是创建 EventSpec
对象的任何地方。
您可以做的是在闭包本身中捕获 dateRange
。
所以您可以像这样重新定义 EventSpec...
struct EventSpec {
var filterClosure: ((Date) -> Bool)?
func provideMatchingEvents(for events: [Event]) {
return events.filters{ filterClosure($0.date) }
}
}
然后像...一样创建它
let dateRange = //some date range that you have already got
let eventSpec = EventSpec(filterClosure: { dateRange.contains($0) })
// in this line the dateRange is captured by the closure so you don't need to capture it as a separate property
我认为这会做您正在尝试做的事情。
关于Swift 4 闭包 : failing to access another local property from within the closure,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49135978/