Swift 5 : What's 'Escaping closure captures mutating 'self' parameter' and how to fix it
The problem is that ContentView
is a struct, which means it's a value type. You can't pass that to a closure and mutate it. If you did, nothing would change, because the closure would have its own independent copy of the struct.
Your problem is that you've mixed your View and your Model. There can be many, many copies of a given View (every time it's passed to a function, a copy is made). You wouldn't want every one of those copies to initiate a request. Instead move this request logic into a Model object and just let the View observe it.
Escaping closure captures mutating 'self' parameter: struct
As you have found, the quick solution is to use a reference type, a class. But why is this the case?
Swift structs are value types, so they are immutable. You can mark a function as mutating
to indicate to the compiler that a function mutates the struct, but what does that actually mean?
Consider a simple struct:
struct Counter {
var count
init(_ count: Int = 0)
{
self.count = count
}
mutating func increment() {
self.count+=1
}
}
Now, try and assign an instance of this to a let
constant:
let someCounter = Counter()
someCounter.increment()
print(someCounter.count)
You will get an error; you need to use a var
.
var someCounter = Counter()
someCounter.increment()
print(someCounter.count)
What actually happens when you call a mutating
func is that a new Counter
is created, with the new count
and it is assigned to someCounter
. It is effectively saying someCounter = Counter(someCounter.count+1)
Now, think what would happen if you could mutate self
in an escaping closure - That new Counter
is going to be created at some unspecified time in the future, but execution has already moved on. It is too late to update someCounter
.
The other advantage of using a class
, as you have found, is that you can use ObservableObject
, which makes updating your SwiftUI views much easier.
SwiftUI Escaping closure captures mutating 'self' parameter
An object's initializer cannot do anything asynchronous. Its job is to produce the object immediately, with all its properties initialized.
SwiftUI: What's 'Escaping closure captures mutating 'self' parameter' and how to fix it
EDIT:
Seems like you cannot mutate structs anymore in escaping closure without removing @escaping which not be possible in your case. You might want to consider changing your implementation to a class.
Structs are immutable. Which mean they cannot be mutated. In your case you are modifying the value of self.bool1 = true
which is changing the value of self.
~~A better way (IMO) would be to create a mutating func
to do your firebase call and update the values inside mutating function.~~
Also, you shouldn’t use State property wrappers in models. They should only be used in views.
Escaping closure captures mutating 'self' parameter
All instances methods receive a reference to self as an implicit first parameter, which is why you have to capture self to call the instance method. Is you don't actually need any instance variables then make doCoolStuff()
a static
function and you will no longer need to call it with self.
(you can use Self.
as of Swift 5, or just the type name ViewModel.
). You can similarly avoid this issue if doCoolStuff
is a closure defined inside of init.
Related Topics
Include Swiftui Views in Existing Uikit Application
Ios 15 Navigation Bar Transparent
Swap Rootviewcontroller With Animation
Generating Random Numbers With Swift
Swift Xcode Index Freezing or Slow
Swiftui - Is There a Popviewcontroller Equivalent in Swiftui
Module Compiled With Swift 3.0 Cannot Be Imported in Swift 3.0.1
How to Document the Parameters of a Function'S Closure Parameter in Swift 3
What's the Difference Between Using Aranchor to Insert a Node and Directly Insert a Node
Check If Key Exists in Dictionary of Type [Type:Type]
Nsfontattributedstring Worked Before Xcode 6.1
Show Am/Pm in Capitals in Swift
Dynamic Row Hight Containing Texteditor Inside a List in Swiftui
Stop a Dispatchqueue That Is Running on the Main Thread
How to Access a Shadowed Top Level Function in Swift
What Is the Use of "Static" Keyword If "Let" Keyword Used to Define Constants/Immutables in Swift