英文:
Reference to captured var in concurrently-executing code
问题
抱歉,代码部分我无法提供翻译。
英文:
I was trying out the new async/await pattern in swift and I came accross something which I found it confusing.
struct ContentView: View {
var body: some View {
Text("Hello World!")
.task {
var num = 1
Task {
print(num)
}
Task {
print(num)
}
}
}
func printScore() async {
var score = 1
Task { print(score) }
Task { print(score) }
}
}
Can someone please clarify looking at the above screenshot on why the compiler only complaints about captured var
inside printScore()
function and does not complaint when the same is being done using the task
modifier on the body
computed property of the ContentView
struct (i.e Line 14-24) ?
This is the example I came up with and got confused on the compiler behavior.I also change the compiler setting "Strict Concurrency Checking” build setting to “Complete” and still don't see the compiler complaining.
答案1
得分: 7
这是@MainActor
的一项特殊功能。在一个View中,body
被标记为 MainActor:
@ViewBuilder @MainActor var body: Self.Body { get }
Tasks继承了它们调用者的上下文,因此它们也是MainActor。如果你在body
中将Task
替换为Task.detached
,你将看到相同的错误,因为这将使Task移出MainActor的上下文。
相反,如果你给printScore
添加@MainActor
,它也会编译通过而没有错误:
@MainActor func printScore() async {
var score = 1
Task { print(score) }
Task { print(score) }
}
score
继承了MainActor的指定,并且是受保护的。对score
没有并发访问,所以这是正确的。
实际上,这适用于所有的actor,但我认为编译器存在一个bug,使事情不完全按照你的期望行事。以下代码会编译通过:
actor A {
var actorVar = 1
func capture() {
var localVar = 1
Task {
print(actorVar)
print(localVar)
}
}
}
然而,如果你移除对actorVar
的引用,传递给Task的闭包将不会放入actor的上下文中,这将使对localVar
的引用无效。在我看来,这是一个编译器的bug。
英文:
This is a special power of @MainActor
. In a View, body
is tagged MainActor:
@ViewBuilder @MainActor var body: Self.Body { get }
Tasks inherit the context of their caller, so those are are also MainActor. If you replace Task
with Task.detached
in body
, you will see the same error, since this will move the Task out of the MainActor context.
Conversely, if you add @MainActor
to printScore
it will also compile without errors:
@MainActor func printScore() async {
var score = 1
Task { print(score) }
Task { print(score) }
}
score
inherits the MainActor designation, and is protected. There is no concurrent access to score
, so this is fine and correct.
This actually applies to all actors, but I believe the compiler has a bug that makes things not quite behave the way you expect. The following code compiles:
actor A {
var actorVar = 1
func capture() {
var localVar = 1
Task {
print(actorVar)
print(localVar)
}
}
}
However, if you remove the reference to actorVar
, the closure passed to Task will not be put into the actor's context, and that will make the reference to localVar
invalid. IMO, this is a compiler bug.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论