1

我正在尝试将 aStateObject actor的初始化程序放在 aasyncApp,但我找不到这样做的方法。

假设我有这个演员:

actor Foo: ObservableObject {
    init() async {
        // ...
    }
}

这导致名义上的错误:

import SwiftUI

struct MyApp: App {
    @StateObject
    var foo = await Foo() //  'async' call cannot occur in a property initializer

    var body: some Scene {
        // ...
    }
}

这会导致类似的错误:

import SwiftUI

struct MyApp: App {
    @StateObject
    var foo: Foo

    init() async {
        _foo = .init(wrappedValue: await Foo()) //  'async' call in a function that does not support concurrency
    }

    var body: some Scene {
        // ...
    }
}

甚至这些也行不通:

import SwiftUI

struct MyApp: App {
    @StateObject
    var foo: Foo

    init() async {
        Task {
            self._foo = .init(wrappedValue: await Foo()) //  Mutation of captured parameter 'self' in concurrently-executing code
        }
    }

    var body: some Scene {
        // ...
    }
}
import SwiftUI

struct MyApp: App {
    @StateObject
    var foo: Foo

    init() async {
        Task { [self] in
            self._foo = .init(wrappedValue: await Foo()) //  Cannot assign to property: 'self' is an immutable capture
        }
    }

    var body: some Scene {
        // ...
    }
}

看来无论我做什么,我都不能Foo成为MyApp. 我在这里想念什么?这当然是可能的。

我在使用 SwiftUI 时也遇到了同样的问题View,所以任何适用于Views 和Apps 的建议都会非常棒!

4

1 回答 1

1

我想告诉你如何解决这个问题:

当您想要初始化某个需要较长时间的 State 值并因此您可能会异步执行它时,您可以使用以下模式:

你从你的“状态”开始,它最初没有被初始化,比如undefined。一种建模方法如下所示:

struct AppState<Value> {
    enum State {
        case undefined
        case initialising
        case idle(Value)
        case mutating(Value)
    }
    var state: State = .undefined
}

显然,您的 AppState 初始状态等于undefined

现在,让我们假设,有一些东西会初始化它(稍后它将是你的视图模型)。当它即将被初始化时,它的状态会从undefined转换为initialising

当它完成时,它的状态从initialising转变为idle

请注意,这里没有什么“异步”——所有状态转换都是“瞬间”发生的。

您可能还会注意到,还有一些附加值,仅出现在 stateidlemutating. 这称为“扩展状态值”。

我还添加了一个“突变”状态,表明您可以在 AppState 上进行突变并相应地将其反映在您的变量 appState 中。

您可能已经感觉到这种建模将我们引向某种“有限状态机”(FSM),它采用这种状态并在接收“输入”时执行突变。其中之一是“初始化”。

您的 ViewModel 现在可以实现这种有限状态机的必要缺失部分:

一组状态(如上)、一组输入(一个枚举)、一组输出(一个枚举)、一个转换函数(纯)和一个输出函数(纯),以及一个将 AppState 转换为某个 ViewState 的函数在视图中呈现。用户操作将通过回调连接起来,最终作为输入值路由到系统中。输出值触发“副作用”,这正是您的异步​​“应用程序状态初始化”功能。副作用返回事件,这些事件再次被路由到系统的输入中。

于 2021-08-25T16:38:19.483 回答