Swift 4 Closure:无法从闭包内访问另一个本地属性

时间:2018-03-06 16:46:11

标签: swift closures

我一直试图在Swift中做一些我认为应该相对简单的事情 - 将一个闭包存储在一个结构中的属性中,这样它就可以用于通过使用该结构的另一个属性来过滤数组。但是我遇到了一个块 - 我不能在struct initialiser中添加闭包,因为它想要引用的变量不存在,我不能把它变成一个惰性变量。它是协议的一部分(不确定这是否会起作用),并且在结构初始化之后我无法分配它,因为它将捕获eI进行赋值的对象的上下文并尝试使用对于当地的财产。简化的方案如下:

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: { date in self.dateRange.contains(date)}

但这并不起作用,因为此时没有self.dateRange。

尝试之后直接或通过“建造者”添加封口。功能不起作用,因为它捕获了自我'它涉及的地方,而不是访问EventSpec的dateRange属性。

我确定这应该是一种常见的模式,而我'遗漏了一些明显的东西,但只能找到引用(很多)将闭包添加为不引用其他属性的变量。

(我意识到如果我在结构中对闭包进行了硬编码,我可以通过标准捕获列表访问局部变量,但这样就无法在运行时定义过滤器。)

任何想法?

1 个答案:

答案 0 :(得分:1)

闭包内部代码的范围在于它所写入的对象中。不是它传入的对象。

所以...

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

这会做你想做的事情。