考虑下面的代码。它使用 AppKit (macOS)
MPMediaItemArtwork
功能来设置 MPNowPlayingInfoCenter
中的图稿。
在运行时,当使用
Swift 6
编译时,会给出警告:
warning: data race detected: @MainActor function at MPMediaItemArtwork/ContentView.swift:22 was not called on the main thread
看来
requestHandler
没有在主线程上调用。添加 @MainActor in
似乎没有任何区别。我可能对 Objective-C 方面有点生疏,但我不知道如何在主线程上返回图像,因为它不允许我使用带有返回值的 Task
,因为它没有不支持并发。
import SwiftUI
import MediaPlayer
struct ContentView: View {
var body: some View {
Text("Test")
.padding()
.task {
await MainActor.run {
let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = [String: Any]()
let image = NSImage(named: "image")!
// warning: data race detected: @MainActor function at MPMediaItemArtwork/ContentView.swift:22 was not called on the main thread
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { _ in
// Not on main thread here!
return image
})
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
}
}
}
}
这是我更新为使用
async/await
的版本,但是它仍然在同一行上给出相同的错误:
extension MPMediaItemArtwork: @unchecked Swift.Sendable {
@MainActor
static func with(image: NSImage) async -> MPMediaItemArtwork {
await withCheckedContinuation { [image] continuation in
continuation.resume(returning: MPMediaItemArtwork(boundsSize: image.size) { [image] _ in
return image
})
}
}
}
.task {
nowPlayingInfo[MPMediaItemPropertyArtwork] = await MPMediaItemArtwork.with(image: image)
}
试试这个,它是一个
AsyncStream
,所以它会分别返回两个值
extension MPMediaItemArtwork {
static func with(image: UIImage) -> AsyncStream<ArtworkReturn> {
return .init { streamContinuation in
let task = Task {
let size: CGSize = await withCheckedContinuation { continuation in
let artwork = MPMediaItemArtwork(boundsSize: image.size) { (size) -> UIImage in
continuation.resume(returning: size)
return image
}
streamContinuation.yield(.artwork(artwork))
}
streamContinuation.yield(.size(size))
streamContinuation.finish()
}
streamContinuation.onTermination = { _ in
task.cancel()
}
}
}
enum ArtworkReturn {
case artwork(MPMediaItemArtwork)
case size(CGSize)
}
}
我没有项目设置,但它应该可以工作。