在Swift中的Dispatch闭包中修改结构实例变量

Modifying struct instance variables within a Dispatch closure in Swift

我正在使用Swift的DEVELOPMENT-SNAPSHOT-2016-06-06-a版本。 我似乎无法解决这个问题,我已经尝试在不同的地方使用@noescape,但是仍然出现以下错误:

Closure cannot implicitly capture a mutating self parameter

为了更好地解释,这是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
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
      }
     }
   }
 }

这些Swift二进制文件中的某些内容现在必须更改,这导致我之前的工作代码损坏。 我要避免的一种解决方法是将struct设置为类,这确实有助于解决问题。 让我知道是否还有其他方法。


我无法测试它,因为我没有使用带有该错误的构建,但是我很确定通过显式捕获自身可以解决此问题:

1
2
3
dispatch_sync(connectQueue) { [self] in
    self.test = 20
}

编辑:显然它不起作用,也许您可以尝试一下(不是很好tbh):

1
2
3
4
5
var copy = self
dispatch_sync(connectQueue) {
    copy.test = 20
}
self = copy

如果您想详细了解原因,请参阅负责任的Swift提案。

新的分派API使得sync方法@noreturn成为可能,因此您不需要显式捕获:

1
2
3
connectQueue.sync {
    test = 20
}


您正在使用Swift3,因为您提到了最近的Swift dev snapshot。 请尝试以下操作,让我知道它是否有效:

1
2
3
4
5
6
7
8
9
10
11
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
        }
    }
}

如果您对其他类型的队列感兴趣,请检查以下内容:

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

异步和异步获取mainQueue

1
2
3
4
5
6
DispatchQueue.main.async {
   //async operations
}
DispatchQueue.main.sync {
    //sync operations
}

如果您对背景感兴趣:

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

您可以参考Swift3中的新功能以及对现有版本的更改:从Swift 2.2迁移到Swift 2.3或Swift 3