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

Original source