标签: swift-concurrency

为什么父任务被取消时,嵌套任务没有被取消?

我需要取消所有嵌套任务我尝试取消其父级但没有任何反应所有嵌套任务继续运行。

private var observationTask: Task<Void, Never>?
...
observationTask = Task {
    Task {
        for await users in list.$users.values {
            updateTableView(withUsers: users)
        }
    }
    Task {
        for await users in list.$users.values {
            updateTableView(withUsers: users)
        }
    }
}
....
observationTask.cancel()
Run Code Online (Sandbox Code Playgroud)

}

swift swift-concurrency

8
推荐指数
1
解决办法
1607
查看次数

Swift:如何将“completion”包装到异步/等待中?

我有一个基于回调的 API。

func start(_ completion: @escaping () -> Void)
Run Code Online (Sandbox Code Playgroud)

我想在该 API 之上编写一个 async/await 包装器,将实现推迟到基于原始回调的 API。

func start() async {
    let task = Task()
    start { 
        task.fulfill()
    }
    
    return await task
}
Run Code Online (Sandbox Code Playgroud)

显然,这段代码没有连接 - 它不是真实的,. 上没有fulfill方法Task

问题:有没有办法在 Swift 中使用非结构化并发来帮助我实现这一目标?

asynchronous async-await swift swift-concurrency

7
推荐指数
1
解决办法
7715
查看次数

从无任务上下文创建常规任务或独立任务的区别?

Task当在无任务上下文中创建(例如,从一些随机AppKit代码)时,创建分离任务或常规任务之间有区别吗?例如,调用

  • Task.detached
  • 或者Task.init

由于该任务没有可继承的参与者,我认为这两个调用必须是等效的,或者是否仍然需要考虑实现差异?

swift swift-concurrency

7
推荐指数
1
解决办法
2738
查看次数

如何使用 SwiftUI 按钮执行异步操作

我想单击 SwiftUI 中的一个按钮来触发 JSON 编码操作。此操作非常耗时,因此我需要它是异步的。我已经尝试了两种解决方案,但它们不起作用。一个主要问题是如何创建异步版本的 json 编码?

\n

解决方案1)

\n
public func encodeJSON<T>(_ value: T, encoder: JSONEncoder, completionHandler: @escaping (Data?, Error?) -> Void) where T: Encodable {\n        DispatchQueue.global().async {\n            do {\n                let data = try encoder.encode(value)\n                DispatchQueue.main.async {\n                    completionHandler(data, nil)\n                    print("finish encode json")\n                }\n            } catch {\n                DispatchQueue.main.async {\n                    completionHandler(nil, error)\n                    print("fail encode json")\n                }\n            }\n        }\n    }\n    \n    public func encodeJSON<T>(_ value: T, encoder: JSONEncoder) async throws -> Data where T: Encodable {\n        \n        try await withUnsafeThrowingContinuation { continuation …
Run Code Online (Sandbox Code Playgroud)

button async-await swift swiftui swift-concurrency

7
推荐指数
1
解决办法
7384
查看次数

@MainActor 闭包似乎没有确定性地在主线程上执行

考虑以下相对简单的 Swift 程序:

import Foundation

func printContext(function: String = #function, line: Int = #line) {
    print("At \(function):\(line): Running on \(Thread.current) (main: \(Thread.isMainThread))")
}

printContext()

Task { @MainActor in
    printContext()
}

Task.detached { @MainActor in
    printContext()
}

Task {
    await MainActor.run {
        printContext()
    }
}

DispatchQueue.main.async {
    printContext()
}

dispatchMain()
Run Code Online (Sandbox Code Playgroud)

根据全球参与者的建议,我预计DispatchQueue.main.async { ...大致相当于Task.detached { @MainActor in ...

然而,在 Swift 5.6.1 上arm64-apple-macosx12.0,该程序似乎在调用时不确定地产生不同的结果。有时我会得到预期的输出:

At main:7: Running on <_NSMainThread: 0x600000083c80>{number = 1, name = main} (main: …
Run Code Online (Sandbox Code Playgroud)

concurrency actor swift swift-concurrency

7
推荐指数
1
解决办法
2110
查看次数

使 @MainActor 类或 actor 符合 Codable

如何向需要与 MainActor 隔离的类添加 Codable 一致性?

例如,以下代码会给出编译器错误:

@MainActor final class MyClass: Codable {
    var value: Int
    
    enum CodingKeys: String, CodingKey {
        case value
    }
    
    init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable'
        let data = try decoder.container(keyedBy: CodingKeys.self)
        self.value = try data.decode(Int.self, forKey: .value)
    }
    
    func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not …
Run Code Online (Sandbox Code Playgroud)

concurrency swift swiftui swift-concurrency

6
推荐指数
1
解决办法
1052
查看次数

在某些情况下,当从任务运行时,swift 异步函数正在主线程上运行

在这种情况下,异步函数读取文件并返回解析的内容。

在我看来,我想从主线程加载内容,然后在完成后更新视图。

我在不同的地方使用过这种模式,并注意到在某些情况下,异步调用是在主线程上(通过调试),而在其他情况下,它是在线程Thread 4 Queue : com.apple.root.user-initiated-qos.cooperative (concurrent)

例如:

struct MyView: View {
  @State var data = "some data"
  var body: some View {
    Button("refresh") {
    // when the button is pressed refresh it
            Task {
                await refresh()
            }
        }.task {
    // when the view appears
            await refresh()
        }
     Text("the data is \(data)") // write the data which was refreshed async
   }


  }
  func refresh() async {
        do {
            let res = try await anotherAyncFunction()
            data = res …
Run Code Online (Sandbox Code Playgroud)

swift swift5 swiftui swift-concurrency

6
推荐指数
2
解决办法
7965
查看次数

SwiftUI Joint - 如何测试等待发布者的异步结果

我正在监听发布者的更改,然后在管道中异步获取一些数据并使用结果更新视图。但是,我不确定如何使其可测试。我怎样才能最好地等到期望得到满足?

看法

struct ContentView: View {
    @StateObject var viewModel = ContentViewModel()

    var body: some View {
        NavigationView {
            List(viewModel.results, id: \.self) {
                Text($0)
            }
            .searchable(text: $viewModel.searchText)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

final class ContentViewModel: ObservableObject {
    @Published var searchText: String = ""
    @Published var results: [String] = []
    private var cancellables = Set<AnyCancellable>()

    init() {
        observeSearchText()
    }

    func observeSearchText() {
        $searchText
            .dropFirst()
            .debounce(for: 0.8, scheduler: DispatchQueue.main)
            .sink { _ in
                Task {
                    await self.fetchResults()
                }
            }.store(in: &cancellables)
    }

    private func fetchResults() …
Run Code Online (Sandbox Code Playgroud)

swiftui combine swift-concurrency

6
推荐指数
1
解决办法
2157
查看次数

Swift:将 AsyncStream 映射到另一个 AsyncStream

更新

\n

接受的答案没有直接回答原来的问题,但帮助解决了我试图解决的根本问题:我想将 AsyncStream (这是一个 AsyncSequence)映射到另一个元素类型为 T2 的 AsyncSequence 中。我在此评论中添加了一些细节。

\n

原问题

\n

我想将 an 映射AsyncStream到另一个AsyncStream。我想知道是否有一个.map可以像数组一样使用的。

\n

引用苹果文档

\n
\n

创建一个异步序列,将给定的闭包映射到异步序列\xe2\x80\x99s 元素上。

\n
\n

下面的代码有错误:

\n
Cannot convert value of type \'AsyncMapSequence<AsyncStream<Int>, Int>\' to specified type \'AsyncStream<Int>\'\n
Run Code Online (Sandbox Code Playgroud)\n

.map据我了解,这是因为在这种情况下的返回类型是AsyncMapSequence<...>而不是AsyncStream<Int>

\n

有没有一种方法可以使用转换函数将 an 映射AsyncStream<T1>到 an ,就像映射到一样?AsyncStream<T2>T1 \xe2\x86\x92 T2Array<T1>Array<T2>

\n

先感谢您!

\n
Cannot convert value of type \'AsyncMapSequence<AsyncStream<Int>, Int>\' to specified …
Run Code Online (Sandbox Code Playgroud)

swift swift-concurrency

6
推荐指数
1
解决办法
2252
查看次数

Swift 并发:@MainActor 对象上的通知回调

语境

在使用 Swift 5.x 和 Xcode 14 构建的 Mac 应用程序中,我有一个控制器对象。该对象具有@PublishedSwiftUI 视图观察到的多个属性,因此我将该对象放置在@MainActor这样的位置:

@MainActor
final class AppController: NSObject, ObservableObject
{
    @Published private(set) var foo: String = ""
    @Published private(set) var bar: Int = 0

    private func doStuff() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

当Mac进入睡眠状态时,这个应用程序需要采取某些操作,因此我在方法中订阅了适当的通知init(),但由于AppController用 装饰@MainActor,我收到此警告:

override init()
{
    NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.willSleepNotification, object: nil, queue: .main) { [weak self] note in
        self?.doStuff()     // "Call to main actor-isolated instance method 'doStuff()' in a synchronous nonisolated context; …
Run Code Online (Sandbox Code Playgroud)

appkit async-await swift swift-concurrency

6
推荐指数
1
解决办法
1654
查看次数