Actor 隔离属性无法将“inout”传递给“async”函数调用

Sam*_*Sam 4 swift swift-concurrency

我是 Swift 并发的新手(我想像大多数人一样),我遇到了编译器错误,我不知道该怎么办。


struct Thing {
  var counter = 0
  mutating func increment() async {
    counter += 1
  }
}

class Controller: UIViewController {
  var thing = Thing()
  
  func mutate() async {
    await thing.increment()
    print(thing.counter)
  }
}

let c = Controller()
Task {
  await c.mutate()
}
Run Code Online (Sandbox Code Playgroud)

mutate()函数的第一行给出了以下错误。 Actor-isolated property 'thing' cannot be passed 'inout' to 'async' function call

如果我只是继承class而不是UIViewController事情工作正常,但我需要这里的控制器,所以我需要弄清楚如何使其在特定的上下文中工作。

Cra*_*ens 5

我认为问题来自于Thing成为struct. 结构体上的func将为.struct 上的属性mutating分配一个新值。为了使其工作,被视为调用中的参数。thingControllerthinginoutthing.increment()

如果你用 anactor代替 a ,struct那么increment()就不需要是 a mutating func,因此thing不会被视为参数inout


一种可能的解决方法是首先创建结构体的副本,然后在副本上调用变异函数,然后将其存储回控制器中的属性上。

func mutate() async {
    var thing = self.thing
    await thing.increment()
    self.thing = thing
    
    print(thing.counter)
}
Run Code Online (Sandbox Code Playgroud)

这是一个问题的原因是 UIViewController 现在都是 actor,因此这些属性被认为是 actor 隔离的。有一个nonisolated关键字,但它不能应用于存储的属性,因此它在这里似乎没有帮助。

如果控制器更改为actor,则错误消息会发生一些变化以表明这一点。

error: cannot call mutating async function 'increment()' on actor-isolated property 'thing'
        await thing.increment()
                    ^
Run Code Online (Sandbox Code Playgroud)