问题 在Swift的Dispatch闭包中修改struct实例变量


我正在使用 DEVELOPMENT-SNAPSHOT-2016-06-06-a Swift的版本。我似乎无法绕过这个问题,我尝试过使用 @noescape 在各个地方,但我仍然有以下错误:

闭包不能隐式捕获变异的自参数

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

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成为一个类,这有助于解决问题。如果有另一种方式,请告诉我。


6096
2018-06-27 15:51


起源

在Mac OS(Xcode版本?)或Linux上? - Martin R
@MartinR我在Mac上使用Xcode 7.3.1 - tfrank377


答案:


我无法测试它,因为我没有使用带有该错误的构建,但我很确定捕获自己 明确地 你可以解决它:

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

编辑:显然它不起作用,也许你可以尝试这个(不是很好tbh):

var copy = self
dispatch_sync(connectQueue) {
    copy.test = 20
}
self = copy

如果你想了解更多关于原因, 这是负责任的Swift提案

新的调度API使得 sync 方法 @noreturn 所以你不需要显式捕获:

connectQueue.sync {
    test = 20
}

11
2018-06-27 18:07



捕获自己仍然给我一个错误: Expected 'weak', 'unowned', or no specifier in capture list。我期待使用新的API,但我想当前的实现没有解决方案? - tfrank377
@tfrank377我编辑了我的答案 - Kametrixom
是的,它有效,但正如你所说,不是很好。我想我会使用类而不是结构来获得更清晰的代码。也就是说,这确实回答了这个问题,并且是我在06/06 Swift快照中看到的最佳解决方案。 - tfrank377
@tfrank377我不会因为它看起来更好而使用一个类。即使它看起来很糟糕,上面的代码甚至没有更差的性能。我建议你为未来的Swift版本添加一个更好的代码的FIXME评论 - Kametrixom
@tfrank377类和结构是两个不同的东西,取决于你需要其中一个的用法。通常,如果您的类型应该像值一样,请使用结构,否则使用类。斯威夫特喜欢价值类型,在他们有意义的地方慷慨 - Kametrixom


你提到最近的一个,你使用的是Swift3 dev snapshot 的 Swift。请尝试以下操作,让我知道它是否有效:

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
        }
    }
}

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

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

得到 mainQueue 异步和同步:

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

如果你对背景感兴趣:

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

您可以在Swift3中引用此功能以及更改现有版本: 从Swift 2.2迁移到Swift 2.3或Swift 3


2
2018-06-27 16:22



我相信这个特别快捷的3快照, DispatchQueue 类不存在。尝试使用它时,我收到“未解析的标识符”错误。 - tfrank377
我们可以看到你的答案受到了启发 stackoverflow.com/a/37806522/1033581 - Cœur