我正在使用Firebase观察事件,然后在完成处理程序中设置图像
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
但是我收到此错误
闭包不能隐式捕获变异的自身参数
我不确定这个错误是什么,寻找解决方案并没有帮助
短版
拥有您的调用的类型FirebaseRef.observeSingleEvent(of:with:)
很可能是值类型(a
struct
?),在这种情况下,变异上下文可能不会self
在@escaping
闭包中显式捕获。
一种简单的解决方案是将您的拥有类型更新为一次引用(class
)。
较长的版本
observeSingleEvent(of:with:)
Firebase的方法声明如下
func observeSingleEvent(of eventType: FIRDataEventType, with block: @escaping (FIRDataSnapshot) -> Void)
所述block
封闭件标有@escaping
参数属性,这意味着它可逃脱其功能的身体,并且甚至寿命self
(在上下文)。利用这些知识,我们构建了一个更简单的示例,我们可以对其进行分析:
struct Foo {
private func bar(with block: @escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
现在,错误消息变得更具说服力了,我们转向在Swift 3中实现的以下演进建议:
@noescape
上下文说明[强调我的]:
除非使用显式的* (因此是不可变的), 否则 捕获
inout
参数(
包括self
在mutation方法中)会成为可逃逸的闭包文字中的错误。
*
现在,这是关键点。对于一个 值
类型(例如struct
),我相信observeSingleEvent(...)
在您的示例中拥有该调用的类型也是这种情况,因此无法进行显式捕获,即afaik(因为我们正在使用值类型,而不是引用)之一)。
解决此问题的最简单方法是使拥有observeSingleEvent(...)
引用类型的类型成为引用类型,例如a class
,而不是a
struct
:
class Foo {
init() {}
private func bar(with block: @escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
请注意,这将self
被强大的参考所捕获;根据您的上下文(我自己没有使用过Firebase,所以我不知道),您可能想显式地捕获self
弱点,例如
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
闭包本身是相当灵活的,可以实现所需功能来让闭包运行而不用类型标注(原文:Closures are inherently flexible and will do what the functionality requires to make the closure work without annotation)。这允许变量捕获灵活地适应使用 情况,有时是移动(moving)有时是借用(borro
问题内容: 我正在尝试将项目更新为Swift 3.0,但遇到了一些困难。我收到下一个错误:“转义的闭包只能按值显式捕获inout参数”。 问题出在此函数内部: 有人可以帮我解决这个问题吗? 问题答案: 仅将参数用于异步任务是一种滥用–就像在调用函数时一样,传递给参数的调用者的值不会更改。 这是因为它不是传递引用,它只是参数的可变影子副本,该副本在函数退出时写回到调用方–并且由于异步函数立即退出,因
问题内容: 这是我的代码(运行): 输出: 问题:第2部分和第3部分有什么区别?为什么第2部分输出“ 44444”而不是“ 43210”? 问题答案: “第2部分”闭包捕获变量“ i”。当闭包(稍后)中的代码执行时,变量“ i”具有在range语句的最后一次迭代中具有的值,即。‘4’。因此 输出的一部分。 “第3部分”在其闭包中未捕获任何外部变量。如规格所述: 每次执行“ defer”语句时,将照
我正在尝试将我的项目更新为Swift 3.0,但我遇到了一些困难。我得到了下一个错误:“转义闭包只能通过值显式捕获inout参数”。 问题出在以下函数内部: 有人可以帮我解决这个问题吗?
考虑以下功能: 当然,我们可以像这样调用它: 但是,提供显式闭包参数会导致编译器抱怨: 这是您的意图吗?阅读的留档时,我没有找到关于参数是否始终被包装的语句,即使在提供闭包时也是如此。我对的理解是: 接受闭包参数。如果参数不是闭包,但与闭包返回的类型相同,则包装它。 然而,我看到的行为是:无论如何都要包装参数。 一个更详细的例子使这在我看来很奇怪: 现在假设我想散列值的键: 为了澄清:的类型是 参
问题内容: Go编译器不应该将循环变量捕获为本地分配的闭包变量吗? 长版: 这也引起了我对C#的困惑,并且我试图理解它。这就是为什么它在C#5.0中已得到修复(原因:循环变量 不能 在循环体内改变)以及未在C#循环中对其进行修复的原因(原因:循环变量 可以 在循环体内改变)。 现在(对我而言),Go中的循环看起来很像C#中的循环,但是尽管事实是我们无法更改这些变量(例如和中)。仍然我们必须首先将它