Modifying struct instance variables within a Dispatch closure in Swift
I cannot test it, because I'm not using a build with that error, but I'm pretty sure by capturing self explicitly you can fix it:
dispatch_sync(connectQueue) { [self] in
self.test = 20
}
EDIT: Apparently it doesn't work, maybe you can try this (not very nice tbh):
var copy = self
dispatch_sync(connectQueue) {
copy.test = 20
}
self = copy
If you want to read more on why, here is the responsible Swift proposal.
The new dispatch API makes the sync
method @noreturn
so you wouldn't need the explicit capture:
connectQueue.sync {
test = 20
}
Swift 2: mutating method on struct not working from inside closure
This seems to work ok:
dispatch_after(time, highQ, { self.callChangeTimeStamp() })
Modifying struct instance using call to name in function parameter
This is an attempt to explain what I had in mind when writing my comment above.
Because there's an asynchronous call to findObjectsInBackgroundWithBlock
, the inout
won't help you here. The idea is to add a callback fetched
like this:
func fetchStats(name: String, var nameOfClass: unit, fetched: unit -> ()) {
// your code as above
query.findObjectsInBackgroundWithBlock {
// your code as above plus the following statement:
fetched(nameOfClass)
}
}
This can be called with
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
nameOfClass = newNameOfClass
}
(all of this code has not been tested)
The point is that you understand that your code is asynchronous (I know, I'm repeating myself). After you have called fetchStats
you don't know when the callback (here: the assignment nameOfClass = newNameOfClass
) will be executed. You cannot assume the assignment has been done after fetchStats
has returned.
So whatever you need to do with the changed nameOfClass
: the corresponding statements must go into the callback:
fetchStats("3-inch Ordnance Rifle", nameOfClass: cannon) { newNameOfClass in
// do whatever you want with the received newNameOfClass
}
Hope this helps.
How to return value from a closure in a Struct in Swift?
You're seeing this error because the closure captures an immutable self
.
Just like primitive types (e.g. Int
), struct
s are value-types, and Swift is built with the notion of immutability of value-types.
In other words, if you had let questionManager = QuestionManager()
, you'd expect questionManager
not to change. Even if it was a var
, it can only mutate via direct action by the caller, e.g. questionManager.doMutatingFunc()
.
But, if a closure was allowed to capture self, it could modify itself at some later point. This is not allowed.
This simplest (only?) way to fix this is to turn QuestionManager
into a class
:
class QuestionManager {
// ...
}
How to define a custom closure that should run when an instance of a struct that uses a custom initializer is run (SwiftUI)
If you add explicit initializer then all properties you want to configure should be in that initializer as well
So the solution is
struct MapView: UIViewRepresentable {
@Binding var showMoreDetails: Bool
var VModel: ViewModel
var token: String
var configure: (MGLMapView) -> () // declare
init(showMoreDetails: Binding<Bool>, VModel: ViewModel, token: String,
configure: @escaping (MGLMapView) -> () = { _ in }) { // last
self.VModel = VModel
self.token = token
self.configure = configure // << initialize !!
_showMoreDetails = showMoreDetails
}
// .. other code
Save struct in background mutating function
I think it will help if we minimally elicit the error message you're getting. (For delay
, see dispatch_after - GCD in swift?.)
struct S {
var name = ""
mutating func test() {
delay(1) {
self.name = "Matt" // Error: Closure cannot ...
// ... implicitly capture a mutating self parameter
}
}
}
The reason lies in the peculiar nature of struct (and enum) mutation: namely, it doesn't really exist. When you set a property of a struct, what you're really doing is copying the struct instance and replacing it with another. That is why only a var
-referenced struct instance can be mutated: the reference must be replaceable in order for the instance to be mutable.
Now we can see what's wrong with our code. Obviously it is legal for a mutating
method to mutate self
; that is what mutating
means. But in this case we are offering to go away for a while and then suddenly reappear on the scene (after 1 second, in this case) and now mutate self
. So we are going to maintain a copy of self
until some disconnected moment in the future, when self
will suddenly be somehow replaced. That is incoherent, not least because who knows how the original self
may have been mutated in the meantime, rendering our copy imperfect; and the compiler prevents it.
The same issue does not arise with a nonescaping closure:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
That's because the closure is nonescaping; it is executed now, so the incoherency about what will happen in the future is absent. This is an important difference between escaping and nonescaping closures, and is one of the reasons why they are differentiated.
Also, the same issue does not arise with a class:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
That's because the class instance is captured by reference in the closure, and a class instance is mutable in place.
(See also my little essay here: https://stackoverflow.com/a/27366050/341994.)
How can you initialize a struct with a closure parameter like this?
This works just like any function whose last parameter is a function. Trailing closure syntax is trailing closure syntax. The fact that the function is an initializer changes nothing.
So let me build up to it in stages. You know you can say:
func myfunc(whatever: () -> ()) {}
myfunc {}
Okay, but now let's make it a static method:
struct S {
static func myfunc(whatever: () -> ()) {}
}
S.myfunc {}
OK, but init
is a static method — it's just a static method whose name you are allowed to omit:
struct S {
let whatever: () -> ()
}
S {} // meaning S.init {}
Related Topics
Is There Any Difference at All Between Suffix(From:) and Dropfirst(_:)
Apple Watch and iPhone Are Not Connected When The App in Phone Goes to Background
Cocoa: Simulating Command+Tab in Cgevent
Dependency Injection in View Controller
iOS App Extension - Action - Custom Data
Uitableview Only Displays One Section
How to Change The Data Type in Realm Database
Swiftui - Button - How to Pass a Function (With Parameters) Request to Parent from Child
Scenekit - Why Scnlight Created Automatically in Scnscene
How to Invoke Method with Cvalistpointer Parameters in Swift
Navigation Bar Items After Push from Swiftui to UIkit
Add UIview (From Xib) with Transparency to Scenekit
Reachability Change Notification Should Be Called Only Once
How to Detect If The User Was Deleted from Firebase Auth
Passing Parameters with #Selector
Swift Making Copies of Passed Class Instances
Vapor 3 - How to Check for Similar Email Before Saving Object