13

I'm using the DEVELOPMENT-SNAPSHOT-2016-06-06-a version of Swift. I cannot seem to get around this issue, I've tried using @noescape in various places, but I still have the following error:

Closure cannot implicitly capture a mutating self parameter

To better explain, here is a simple example:

public struct ExampleStruct {
  let connectQueue = dispatch_queue_create("connectQueue", nil)
  var test = 10

  mutating func example() {
    if let connectQueue = self.connectQueue {
      dispatch_sync(connectQueue) {
        self.test = 20 // error happens here
      }
     }
   }
 }

Something must have changed in these Swift binaries that is now causing my previously working code to break. A workaround I want to avoid is making my struct a class, which does help in fixing the issue. Let me know if there is another way.

Cœur
  • 37,241
  • 25
  • 195
  • 267
tfrank377
  • 1,858
  • 2
  • 22
  • 34

2 Answers2

12

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
}
Kametrixom
  • 14,673
  • 7
  • 45
  • 62
  • Capturing self still gives me an error: `Expected 'weak', 'unowned', or no specifier in capture list`. I look forward to using the new APIs, but I guess there is no solution with the current implementation? – tfrank377 Jun 27 '16 at 18:52
  • Yeah it works, but as you said, not very nice. I think I will use a class instead of a struct in order to have cleaner code. That said, this does answer the question and is the best solution I see for the 06/06 Swift snapshot. – tfrank377 Jun 27 '16 at 19:11
  • @tfrank377 I wouldn't use a class just because it looks better. The above code doesn't even have worse performance even though it looks bad. I suggest you to add a FIXME comment with the much better code for future Swift versions – Kametrixom Jun 27 '16 at 19:13
  • that is another option. Is there any downside to using a class though? – tfrank377 Jun 27 '16 at 19:19
  • 1
    @tfrank377 Classes and structs are two different things, depending on usage you need one of them. Generally if your type should behave like a value, use a struct, otherwise a class. Swift loves value types, be generous with them where they make sense – Kametrixom Jun 27 '16 at 19:42
2

You are using Swift3 since you mentioned a recent dev snapshot of Swift. Try below and let me know if it works:

public struct ExampleStruct {
    let connectQueue = DispatchQueue(label: "connectQueue", attributes: .concurrent)//This creates a concurrent Queue

    var test = 10

    mutating func example() {
        connectQueue.sync { 
            self.test = 20
        }
    }
}

If you are interested in other types of queues, check these:

let serialQueue = DispatchQueue(label: "YOUR_QUEUE", attributes: .serial)
serialQueue.sync { 
    //
}

Get the mainQueue asynchronously and synchronously:

DispatchQueue.main.async {
   //async operations
}
DispatchQueue.main.sync {
    //sync operations
}

And if you are interested in Background:

DispatchQueue.global(attributes: .qosDefault).async {
  //async operations
}

You could refer this for new features in Swift3 and for changes to existing version: Migrating to Swift 2.3 or Swift 3 from Swift 2.2

Santosh
  • 2,900
  • 1
  • 16
  • 16
  • I believe in this particular swift 3 snapshot, the `DispatchQueue` class does not exist. I get the "unresolved identifier" error when trying to use it. – tfrank377 Jun 27 '16 at 18:44
  • we can see that your answer was inspired by https://stackoverflow.com/a/37806522/1033581 – Cœur Aug 20 '17 at 15:36