. Advertisement .
..3..
. Advertisement .
..4..
I am working with programs and getting the error message:
Closure cannot implicitly capture a mutating self parameter
Here is the detail of the code that I ran:
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")!
}
})
I need an explanation for the problems I’ve encountered. How to fix escaping closure captures mutating ‘self’ parameter?
The cause:
FirebaseRef.observeSingleEvent(of:with:) is a
struct
, it’s also a type of value. In this case a mutating context doesn’t know that you are mutating and bindingself
in an @escaping closure. Therefore, the error happens.Solution:
For short versions:
You only need to update your current type to a reference one with
class
.For longer versions:
You also can change your current type
observeSingleEvent(...)
into a reference type like aclass
, it’s better than astruct
:If you want to capture
self
weakly or strongly, it’s depends on your case. For example:Sync Solution
If you want to modify a value type (
struct
), it may not work for async calls. However, it will work synchronously if you write it this way:A “mutating self”, with different value types, cannot be captured by any other means than providing a copy (hence
var
).Why not Async instead?
This is because you can’t mutate
result
with no compiler error. However, you cannot return the mutated result toself
. Despite the fact that there will be no error,self
won’t change since the closure ofpeel()
is not dispatched.You can try to circumvent this by changing your code to make the async calls synchronous. Wait for the call to complete. Although technically possible, it is unlikely that this will serve the purpose of the async API with which you are interacting. You should change your approach.
Although technically sound, changing
struct
toclass
doesn’t solve the problem. As an example, theclass Banana
property can be changed synchronously by anyone-knows-when. This is difficult to understand and will lead to problems. It’s better to write an API handler outside of the model and then fetch and modify the model object upon completion. This is because it doesn’t have enough context. I assume that this is model code sinceself.img
has been mutated in OP’s source code.It may be possible to add “async corruption” objects.
This is what I am thinking of:
BananaNetworkRequestHandler
executes requests simultaneously and reports the result to aBananaStore
BananaStore
will then look forpeelingResult.bananaID
on its inside and take theBanana
appropriateBanana
.banana.bananaID == peelingResult.bananaID
it setsbanana.isPeeled = peelingResult.isPeeled
.It is easy to see that the search for a simple solution can quickly become complicated, especially if you need to change the architecture of an app.