使用 AppKit MPMediaItemArtwork 函数进行 Swift 数据竞赛

问题描述 投票:0回答:1

考虑下面的代码。它使用 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)
}
swift macos avplayer appkit mpmediaitem
1个回答
0
投票

试试这个,它是一个

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)
    }
}

我没有项目设置,但它应该可以工作。

© www.soinside.com 2019 - 2024. All rights reserved.