I have encountered the problem "Cannot assign to property: 'self' is an immutable capture". How can i call API to check status and update "getUpdateSuccess" parameter
struct HomepageViewModel {
var getUpdateSuccess: Bool = false
init() {
getStatusUpdated.execute().done {
[self] isUpdated in
// Cannot assign to property: 'self' is an immutable capture
self.getUpdateSuccess = isUpdated
}
}
}
If you want to “reference” self
later (e.g., update the same instance later), self
should be a reference type, not a value type.
So you can solve this by making the view model a class
(a reference type) rather than a struct
(a value type).
“Model” objects are good candidates for value types, but “view models” are generally reference types. See Value and Reference Types for a discussion of when you might use a value type and when you might use a reference type. For a general discussion, see The Swift Programming Language: Structures and Classes.
By the way, the closure’s capture list syntax (the stuff in between the [
and the ]
) has different practical implications if the captured variable is a reference type vs when it is a value type.
With a value type, the capture list makes sure you have a copy of the value:
struct Person {…}
var person = Person(…)
foo { [person] in
// this code will be dealing with a safe copy of the original `Person`
}
// maybe you’ll mutate the original `Person` instance here,
// but the above closure will have a copy of the original one
Contrast that with a reference type, where the capture list makes sure you have a strong reference to the reference type:
class ViewModel {
func bar() {
baz { [self] in
// this has a strong reference to this view model instance, not a copy of the instance
}
}
}
let viewModel = ViewModel(…)
viewModel.bar() // any updates that bar does asynchronously, will update this instance of the view model, not a copy of it
As an aside, with reference types, you will often see a capture list with the weak
keyword, e.g., [weak self]
, if you want a “weak” reference to the class rather than a strong reference. This is common if you need to prevent a “strong reference cycle” (a topic beyond the scope of this conversation). This is discussed in The Swift Programming Language: Strong Reference Cycles for Closures.
But, whether a strong reference or weak reference, you are not dealing with a copy of the object, but rather a “reference” to the same original instance.