在后台队列上创建NSAttributedString。"[NSCell init]必须只从主线程使用"

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

我有一个基于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。通过以下方式获得对abc.txt的读写权限 NSFileCoordinator
    • 线程2(bg)现在在NSFileCoordinator区块中。
  2. 主题1(主要): 用户发起的NSD文件保存,NSD文件请求通过写访问abc.txt。NSFileCoordinator
    • 线程1(MAIN)现在被阻塞,等待线程2的文件协调器锁。
  3. 线程2(bg队列): 在文件协调器块中前进......,试图初始化NSAttributedString,哦,它包含一个附件,无法初始化。NSTextAttachmentCell 在后台队列中,让我把这个交给主队列,真正的快速...... ⚡️ DEADLOCK ⚡️ ...
    • 线程2(bg)现在正在等待线程1(main),线程1在其文件协调器访问块前等待线程2(bg)完成其文件协调器块。
multithreading cocoa nsattributedstring nstextattachment nscell
1个回答
0
投票

你不应该忽略主线程的警告。如果你使用 main.async 而非 sync 添加附件应该不会有问题。这个参考文献 也有助于定义哪些类在不同线程中表现良好。一般来说,任何AppKit视图类型的类都应该只在主线程上使用。

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