【问题标题】:Avoid blocking the main thread in a NSDraggingSession using a NSPasteboardItemDataProvider避免使用 NSPasteboardItemDataProvider 阻塞 NSDraggingSession 中的主线程
【发布时间】:2015-09-05 18:26:12
【问题描述】:

在 Mac OS X 应用程序 (Cocoa) 中,我使用 NSDraggingSession 将一些图像从我的应用程序复制到其他应用程序。 NSDraggingItem 使用实现协议NSPasteboardItemDataProvider 的对象,在用户丢弃它时提供数据。

当我处理图像时,涉及的类型有:NSPasteboardTypePNGkPasteboardTypeFileURLPromisekUTTypeFileURLcom.adobe.photoshop-imagepublic.svg-image。这些图像位于远程位置,因此在将它们提供给粘贴板之前,我必须从 Internet 下载它们。

我实现了方法- pasteboard(pasteboard:item:provideDataForType:) 做这样的事情:

  • 如果请求的类型是kPasteboardTypeFileURLPromise,我会获取粘贴位置,并在粘贴板中构建和设置 URL 字符串以及将来应该写入文件的位置。

  • 如果请求的类型是kUTTypeFileURL,我下载文件,指定一个临时位置并将下载的文件写入该位置。然后,我在粘贴板中设置了该位置的 URL 字符串。

  • 如果请求的类型是其他类型之一,我下载文件并在粘贴板中设置纯 NSData

所有这些操作都在主线程上执行,产生了一些我想摆脱的滞后。

我尝试在后台线程上执行这些操作,然后返回主线程在粘贴板中设置最终数据,但这不起作用,因为该方法之前完成。

有人知道实现它的方法吗?

【问题讨论】:

  • 据我发现,仅 NSPasteboard API 无法返回您打算写入文件的 URL,但允许您写入它是异步的。我与一位 Apple 工程师交谈过,他建议在编写文件时使用 NSFileCoordinator,但并非所有目标应用程序都会尊重这一点。
  • 问题是我需要先下载并写入文件,然后再告诉粘贴板将在哪里,因为如果我异步执行此操作,目标应用程序会在它被写入并找到之前执行它没有。同步解决方案尊重执行顺序就好了,但是阻塞了主线程。
  • 是的,这是有道理的。祝你好运;这个 API 既旧又笨重。你可能在cocoa-dev 名单上也有一些运气。

标签: macos cocoa nspasteboard nsdraggingitem


【解决方案1】:

粘贴板类型的承诺通常意味着您已经拥有的另一种数据格式,您希望避免在必要之前进行转换的时间和内存费用。我认为使用它来推迟下载任何数据根本不合适。一方面,当最终请求下载时,下载可能会失败。另一方面,这可能需要任意长的时间,就像你现在正在努力的那样。

所以,我认为你应该提前下载数据。要么将其保存在内存中,要么将其保存到临时文件中。如果合适,使用承诺的类型以不同的形式交付,但要提前准备好。

【讨论】:

  • 我使用数据提供者正是为了避免提前做所有额外的工作,因为我支持多种类型,直到最后一次我才知道哪个类型会被其他应用程序。我认为事先下载所有内容不是一个好主意,因为我有数百张不同类型的图像,并且用户可以在每次操作中仅请求一种具体类型中的一张。正如我在文档中所读到的,这是提供者数据的工作,但为了使其工作,我必须同步完成所有工作,阻塞主线程。我想避免这种情况。
  • 没有办法避免这种情况。来自粘贴板服务器的请求是同步的。在从它调用的方法返回之前,您必须得到答复。您应该考虑复制粘贴是否是您需要的正确模型。至少,一次复制粘贴这么多不同的项目。也许允许用户在您的应用中只选择一件事并将其放在粘贴板上(在下载必要的基础数据之后)。
猜你喜欢
  • 2011-10-18
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多