Swift 6中使用MPMediaItemArtwork遇主线程数据竞争警告求助
解决MPMediaItemArtwork requestHandler主线程执行问题
问题根源
MPMediaItemArtwork的requestHandler回调会被系统在后台线程触发,Swift 6的并发安全检查会检测到NSImage(AppKit UI组件)在非主线程被访问,从而抛出数据竞争警告。你之前尝试的async/await扩展只是在主线程创建MPMediaItemArtwork实例,但无法改变requestHandler的执行线程,因此警告依然存在。
解决方案:强制在主线程执行requestHandler逻辑
因为requestHandler是同步回调(必须立即返回图片),可以用DispatchQueue.main.sync将图片返回逻辑强制切换到主线程执行,确保NSImage的操作在主线程完成:
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]() guard let image = NSImage(named: "image") else { return } nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { _ in // 强制在主线程执行图片返回逻辑 return DispatchQueue.main.sync { image } } nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo } } } }
补充说明
为什么用
sync而不是async?
requestHandler要求同步返回结果,async会导致回调提前返回空值,不符合API要求;sync会阻塞当前后台线程,直到主线程完成图片返回操作,确保数据一致性。额外优化:提前预处理图片
如果图片需要裁剪、缩放等操作,可以提前在主线程完成处理,保存为CGImage或预渲染的NSImage,再在requestHandler中直接返回,减少主线程阻塞:
// 主线程提前处理图片(示例:缩放图片) let targetSize = NSSize(width: 300, height: 300) let processedImage = NSImage(size: targetSize) { rect in image.draw(in: rect) } nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: processedImage.size) { _ in DispatchQueue.main.sync { processedImage } }
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

