cod*_*999 51 ios firebase swift firebase-realtime-database swift3
我正在使用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")!
}
})
Run Code Online (Sandbox Code Playgroud)
但是我收到了这个错误
闭包不能隐式捕获变异的自身参数
我不确定这个错误是什么,搜索解决方案没有帮助
dfr*_*fri 71
简短的版本
拥有您调用的类型FirebaseRef.observeSingleEvent(of:with:)
很可能是值类型(struct
?),在这种情况下,变异上下文可能不会self
在@escaping
闭包中显式捕获.
简单的解决方案是将您拥有的类型更新为引用一次(class
).
版本较长
observeSingleEvent(of:with:)
Firebase的方法声明如下
Run Code Online (Sandbox Code Playgroud)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 */
}
}
Run Code Online (Sandbox Code Playgroud)
现在,错误消息变得更有说服力,我们转向在Swift 3中实现了以下进化提议:
陈述[强调我的]:
捕获
inout
参数(包括self
在变异方法中)会成为可逃避的闭包文字中的错误,除非捕获是显式的(从而是不可变的).
现在,这是一个关键点.对于值类型(例如struct
),我认为对于observeSingleEvent(...)
在您的示例中拥有调用的类型也是如此,这样的显式捕获是不可能的,afaik(因为我们使用的是值类型,而不是引用一).
解决此问题的最简单方法是使类型拥有observeSingleEvent(...)
引用类型,例如a class
,而不是struct
:
class Foo {
init() {}
private func bar(with block: @escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这将self
通过强有力的参考捕获; 取决于你的上下文(我自己没有使用Firebase,所以我不知道),你可能想要明确地捕获self
弱,例如
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Run Code Online (Sandbox Code Playgroud)
cti*_*tze 18
如果你需要改变一个struct
闭包中的值type(),它可能只能同步工作,但不能用于异步调用,如果你这样写:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
Run Code Online (Sandbox Code Playgroud)
除非通过提供可变(因此var
)副本,否则您无法以值类型捕获"变异自我" .
这在异步上下文中不起作用的原因是:您仍然可以在result
没有编译器错误的情况下进行变异,但是您无法将变异结果分配回来self
.仍然,没有错误,但self
永远不会改变因为方法(peel()
)在调度闭包之前退出.
为了避免这种情况,您可以尝试更改代码,以通过等待它完成来将异步调用更改为同步执行.虽然技术上可行,但这可能会破坏您正在与之交互的异步API的目的,并且您最好改变您的方法.
更改struct
为class
技术上合理的选项,但不解决实际问题.在我们的示例中,现在是a class Banana
,其属性可以异步更改who-know-when.这会带来麻烦,因为它很难理解.您最好在模型本身之外编写API处理程序,并在完成执行获取并更改模型对象之后.没有更多的背景,很难给出一个合适的例子.(我假设这是模型代码,因为self.img
在OP的代码中发生了变异.)
我正在考虑以下几点:
BananaNetworkRequestHandler
异步执行请求,然后将结果报告BananaPeelingResult
给aBananaStore
BananaStore
随后采取适当Banana
的寻找来自其内部peelingResult.bananaID
banana.bananaID == peelingResult.bananaID
,然后设置banana.isPeeled = peelingResult.isPeeled
,您可以看到,从寻找简单修复的过程中,它可以很容易地参与进来,特别是如果必要的更改包括更改应用程序的体系结构.
Nik*_*iev 13
如果有人绊倒了这个页面(来自搜索)并且你正在定义一个protocol
/ protocol extension
,那么如果你声明你protocol
的类绑定可能会有所帮助.像这样:
protocol MyProtocol: class {
...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
25901 次 |
最近记录: |