Swift,actor:演员隔离属性“扫描”无法从非隔离上下文中改变。

34

我有一个演员:

actor StatesActor {

    var job1sActive:Bool = false
    ...

}

我有一个使用那个演员的对象:

class MyObj {
    
    let myStates = StatesActor()
    
    func job1() async {
    
        myStates.job1IsActive = true

    }
}

行:

myStates.job1IsActive = true

出现以下错误:

来自非隔离上下文的尝试改变Actor-isolated属性“job1IsActive”

如何使用Actor正确地存储/读取状态信息,以便MyObj可以使用它来读取和设置状态?


4
在你的角色中创建一个函数来更新属性,然后 MyObj应该调用该函数。 - Rob
2个回答

40

如何使用演员正确地存储/读取状态信息,以便 MyObj 可以使用它来读取和设置状态?

您不能从演员外部改变演员的实例变量。这就是演员的全部目的!

相反,给演员一个方法来设置它自己的实例变量。然后,您将能够调用该方法(使用await)。


我需要在StatesActor中将其包装在一个方法中...谢谢。 - zumzum
1
基本上,这个演员正在“教”你如何安全地使用多线程。 - matt
7
异步属性设置器在理论上是可行的,但Swift目前尚未支持。 - Berik
10
等待主要角色运行 { ... 在此设置您可爱的属性... } - JAHelia
直到今天,当我安装了Xcode 14b4之后,我仍然可以毫无问题地编写await myActor.foo = bar - Rick
2
我有一个非actor模型,其中包含一个@MainActor属性,所以这样可以工作: 代码 }``` - spfursich

6

不允许在未在演员上运行的代码中使用属性设置器(“演员隔离代码”是确切的术语)。最好的方式是从演员本身的代码中进行状态变更。在您的情况下:

actor StatesActor {
    var job1IsActive: Bool = false
    func startJob1() {
        job1IsActive = true
        ...
    }
}
class MyObj {
    let myStates = StatesActor()
    func job1() async {
        await myStates.startJob1()
    }
}

异步属性设置器在理论上是可能的,但是不安全。这也许就是为什么 Swift 没有它们的原因。这会使得编写类似于 if await actor.a == nil { await actor.a = "Something" } 这样的代码变得太容易了,其中 actor.a 可以在调用 getter 和 setter 之间发生变化。

上面的答案在大多数情况下都有效(并且足以回答提出的问题)。然而,在某些情况下,需要从演员外部的代码中改变演员的状态。对于 MainActor,可以使用 MainActor.run(body:)。对于全局演员,可以将 @NameOfActor 应用于函数(并可用于定义类似于 MainActorrun 函数)。在其他情况下,可以在函数的演员参数前使用 isolated 关键字:

func job1() async {
    await myStates.startJob1()
    let update: (isolated StatesActor) -> Void = { states in
        states.job1IsActive = true
    }
    await update(myStates)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接