在后台队列上创建 NSAttributedString:"[NSCell init] must be used from main thread only"



我有一个基于NSDocument的Cocoa应用程序,可以向用户显示文本文档。文档内容在后台队列中读取,这会导致问题:

我将NSAttributedString与图像一起使用,即它可以包含NSTextAttachmentNSTextAttachmentCell。当我尝试初始化图像的附件并在 Xcode 中激活主线程检查器时,出现以下错误:

// On background queue:
let attachment = NSTextAttachment()
attachment.attachmentCell = NSTextAttachmentCell(imageCell: image) <-
"[NSCell init] must be used from main thread only"

我的第一次尝试是将该代码包装在DispatchQueue.main.sync {}中,但这会导致在自动保存或用户保存文档时偶尔与NSDocument死锁。

自动保存会阻塞主队列,我的代码会在后台运行尝试读取文档,但这最终陷入了僵局,因为我无法调用主队列来创建文本附件。

我的问题:

我是否可以忽略 Xcode 中的主线程检查器并在后台队列上实例化NSTextAttachmentCell

我在后台队列上所做的只是使用其附件初始化属性字符串。对主队列进行了进一步修改。

事件的顺序

  1. 线程 2(bg 队列(:由于某种原因需要更新 abc.txt。通过NSFileCoordinator获取对 abc .txt的读/写访问权限
    • 线程 2 (bg( 现在在 NSFileCoordinator 块中
  2. 线程
  3. 1(主线程(:用户启动的 NSDocument 保存,NSDocument 请求对 abc 的写入访问权限.txt通过NSFileCoordinator线程
    • 1(主(现在被阻止,正在等待线程 2 的文件协调器锁定
  4. 线程 2(bg 队列(:在文件协调器块中移动...,尝试初始化 NSAttributedString,哦,它包含一个附件,无法初始化后台队列上的NSTextAttachmentCell,让我把它交给主队列真正的'快速' ...⚡️ 僵局 ⚡️
    • 线程 2 (bg( 现在正在等待线程 1 (MAIN(,线程 1 (MAIN( 在其文件协调器访问块前面等待线程 2 (bg( 完成其文件协调器块。

不应忽略主线程警告。如果您使用main.async而不是sync则添加附件应该永远不会有问题。此参考还有助于定义哪些类在不同线程中表现良好。一般来说,任何 AppKit 视图类型类都应仅在主线程上使用。

相关内容

最新更新