Build

AsyncValue

这是一个简单的包,它提供了一个围绕 AsyncStream 的便捷属性包装器,其行为几乎与 @Published 完全相同。

安装

通过 Xcode

  1. 在左侧的项目导航器中,单击您的项目
  2. 单击 Package Dependencies(软件包依赖项)
  3. 在搜索栏中输入:https://github.com/BrentMifsud/AsyncValue.git
  4. 选择所需的版本,然后单击 Add Package(添加软件包)

通过 Package.swift

在您的 Package.swift 文件中,添加以下内容

let package = Package(
    name: "MyPackage",
    dependencies: [
        .package(url: "https://github.com/BrentMifsud/AsyncValue.git", from: .init(1, 0, 0))
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "MyPackage",
            targets: ["MyPackage"]
        ),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "MyPackage",
            dependencies: ["AsyncValue"]
        ),
        .testTarget(
            name: "MyPackageTests",
            dependencies: ["MyPackage"]
        ),
    ]
)

用法

访问当前值

@AsyncValue var myValue: String = "Test"

print(myValue) // prints: test

观察值的变化

就像支持 @Published 的 publisher 一样,AsyncValue 由 AsyncStream 支持。 您可以订阅值的更新。

@AsyncValue myValue: String = "Test"

Task {
    for await value in myValue {
        print("Value: \(value)")
    }
}

Task {
    await Task.sleep(nanoseconds: 1_000_000_000)
    myValue = "New Value"
}

/* Prints:
Value: test
Value: New Value
*/

使用多个任务进行观察

AsyncStream 的一个主要限制是,您只能使用单个任务对其进行 for-await-in 操作。

AsyncValue 没有此限制

@AsyncValue myValue: String = "Test"

Task {
    for await value in myValue {
        print("Task 1 Value: \(value)")
    }
}

Task {
    for await value in myValue {
        print("Task 2 Value: \(value)")
    }
}

Task {
    await Task.sleep(nanoseconds: 1_000_000_000)
    myValue = "New Value"
}

/* Prints (note that the order of the tasks printing may vary as this is happening asyncronously):
Task 1 Value: test
Task 2 Value: test
Task 2 Value: New Value
Task 1 Value: New Value
*/

与 SwiftUI 一起使用

ObservableObject 支持

只需一行代码,即可调整 AsyncValue 以与 ObservableObject 无缝协作

class MyObservableObject: ObservableObject {
    @AsyncValue var myValue: String = "Test"
}

AsyncValue 的任何更改都将以与 @Published 相同的方式触发视图更新。

感谢 jlsiewert 提出了这个很酷的技巧,使它可以自动工作。

AsyncSequence 的 .onReceive 等效项

还有一个 .onRecieve(sequence:perform:) 视图修饰符,允许您响应来自任何 AsyncSequence 的更改。

struct MyView: View {
    var body: some View {
        Text("Hello World!")
            .onReceive(myService.$myValue) { value in
                print("The value changed to: \(value)")
            }
    }
}

class MyService: ObservableObject {
    @AsyncValue var myValue: String = "Test"
}