Avoid blocking the main thread in a NSDraggingSession using a NSPasteboardItemDataProvider
Asked Answered
C

1

6

In a Mac OS X app (Cocoa), I'm copying some images from my app to others using a NSDraggingSession. The NSDraggingItem makes use of an object that implements the protocol NSPasteboardItemDataProvider, to provide the data when the user drops it.

As I'm dealing with images, the types involved are: NSPasteboardTypePNG, kPasteboardTypeFileURLPromise, kUTTypeFileURL, com.adobe.photoshop-image and public.svg-image. These images are in a remote location, so before I can provide them to the pasteboard, I have to download them from the Internet.

I implement the method - pasteboard(pasteboard:item:provideDataForType:) doing something like this:

  • If the type requested is kPasteboardTypeFileURLPromise, I get the paste location and build and set in the pasteboard the URL string with the location where the file is supposed to be written in the future.

  • If the type requested is kUTTypeFileURL, I download the file, specify a temporal location and write the downloaded file to that location. Then, I set in the pasteboard the URL string of the location.

  • If the type requested is one of the others, I download the file and set the plain NSData in the pasteboard.

All these operations are performed on the main thread, producing some lags that I want to get rid of.

I've tried to perform these operations on a background thread, and come back to the main thread to set the final data in the pasteboard, but this doesn't work because the method finishes before.

Does anyone know a way to achieve it?

Crowbar answered 5/9, 2015 at 18:26 Comment(3)
As far as I have found, the NSPasteboard API alone doesn't have a way to return a URL to which you intend to write a file, but allow you to write it asynchronously. I spoke with an Apple engineer who recommended using NSFileCoordinator when writing the file, but not all destination apps will respect this.Woebegone
The thing is that I need to download and write the file before I tell the pasteboard where is going to be, because if I do it asynchronously, the destination app goes for it before it gets written and finds nothing. The synchronous solution respects the order of execution just fine, but blocking the main thread.Crowbar
Yep, that makes sense. Best of luck; this API is old and clunky. You might have some luck on the cocoa-dev list as well.Woebegone
E
0

Promises of pasteboard types are usually meant to be an alternative format of data that you already have, where you want to avoid the expense in time and memory of converting before it's necessary. I don't think it's really appropriate to use it to defer downloading any of the data, at all. For one thing, the download could fail when it's ultimately requested. For another, it could take an arbitrarily long time, as you're struggling with now.

So, I think you should download the data in advance. Either keep it in memory or save it to a temporary file. Use promised types, if appropriate, to deliver it in different forms, but have it on hand in advance.

Ensoll answered 5/9, 2015 at 20:44 Comment(2)
I use a data provider precisely to avoid doing all that extra work in advance, given that I support several types and I don't know until the very last time which one is going to be requested by the other app. I don't think is a good idea to download everything beforehand because I have hundreds of images, in different types, and the user could request, in each operation, just one of then in one concrete type. As I read in the docs, that's the work of the provider data, but in order to make it work I have to do all synchronously, blocking the main thread. I want to avoid that.Crowbar
There is no way to avoid that. The request from the pasteboard server is synchronous. You have to have the reply before returning from the method it called. You should consider if copy-paste is the right model for what you need. At least, copy-paste of so many different items at once. Perhaps allow the user to select just one thing in your app and put that on the pasteboard (after downloading the necessary base data).Ensoll

© 2022 - 2024 — McMap. All rights reserved.