Closure cannot implicitly capture a mutating self parameter
firebase, firebase-realtime-database, ios, swift, swift3
Solution
The short version
The type owning your call to `FirebaseRef.observeSingleEvent(of:with:)` is most likely a value type (a `struct`?), in which case a mutating context may not explicitly capture `self` in an `@escaping` closure.
The simple solution is to update your owning type to a reference once (`class`).
The longer version
The `observeSingleEvent(of:with:)` method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: @escaping (FIRDataSnapshot) -> Void)
The `block` closure is marked with the `@escaping` parameter attribute, which means it may escape the body of its function, and even the lifetime of `self` (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
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 */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
- SE-0035: Limiting inout capture to `@noescape` contexts
Stating [emphasis mine]:
Capturing an `inout` parameter, including `self` in a mutating method, becomes an error in an escapable closure literal, unless the capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. `struct`), which I believe is also the case for the type that owns the call to `observeSingleEvent(...)` in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the `observeSingleEvent(...)` a reference type, e.g. a `class`, rather than a `struct`:
class Foo {
init() {}
private func bar(with block: @escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture `self` by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture `self` weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Problem
I am using Firebase to observe event and then setting an image inside completion handler ``` 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")! } }) ``` However I am getting this error Closure cannot implicitly capture a mutating self parameter I am not sure what this error is about and searching for solutions hasn't helped