filePromiseProvider writePromiseTo URL не работает при перетаскивании изображения в другое приложение

У меня есть File Promises, реализованный в приложении Какао, которое позволяет перетаскивать изображения из вида и помещать их в папки на компьютере или в приложения, такие как предварительный просмотр или evernote. В прошлом это работало хорошо с использованием делегата NSDraggingSource и метода namesOfPromisedFilesDropped. Этот метод вернул бы место размещения и позволил бы мне записать данные изображения прямо туда. Таким образом, при переходе к значку приложения, например предварительного просмотра, или в приложении, таком как evernote, файл записывается и приложение либо загружается, либо изображение просто отображается внутри.

К сожалению, этот метод устарел в 10.13, поэтому он больше не вызывается в новых версиях ОС. Вместо этого я переключился на использование метода filePromiseProvider writePromiseTo url делегата "NSFilePromiseProviderDelegate". Этот метод вызывается, и данные изображения обрабатываются. Я получаю целевой URL и пытаюсь записать данные изображения в это место. Это прекрасно работает при простом перетаскивании в папки на Mac. Но при перетаскивании на другие значки приложений, например Preview.app, или непосредственно в папку в Evernote, я получаю сообщение об ошибке "Ошибка домена =NSPOSIXErrorDomain Code=2 " Нет такого файла или каталога ".

Я попытался сделать это, используя полные URL-адреса и URL-пути. Независимо от того, перетаскивается ли оно в другие приложения, оно просто не позволит удалить или создать файл в этом месте.

Есть ли какие-то права, которые могут отсутствовать? Я даже попытался найти исходный код Apple, найденный здесь с той же ошибкой: File Promises Source

Вот код, который я сейчас использую, который возвращает ошибку с невозможностью записи во внешние местоположения приложения. Это работает только для перетаскивания в папки на компьютере.

extension DragDropContainerView: NSFilePromiseProviderDelegate {
    internal func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
        let fileName = NameFormatter.getFormattedNameFromDate() + "." + fileType.getFileType().typeIdentifier
        return fileName
    }

    internal func operationQueue(for filePromiseProvider: NSFilePromiseProvider) -> OperationQueue {
        return workQueue
    }

    internal func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {
        if let snapshot = filePromiseProvider.userInfo as? SnapshotItem {
            if let data = snapshot.representationData {
                do {
                    try data.write(to: url)
                    completionHandler(nil)
                } catch {
                    completionHandler(error)
                }
            }
        }
    }
}

Любая помощь по этому вопросу была бы отличной. В конечном счете, я просто хочу иметь возможность перетаскивать изображение в приложение, и оно должно принимать перетаскивание. Раньше это работало, но больше не работает.

Обновление 1: После долгих экспериментов мне удалось найти "решение", которое работает. Я не понимаю, почему это работает, но кое-как, как это в конечном итоге запускает поток, который запускает старый "устаревший" метод.

Я создаю перетаскиваемый элемент;

let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardWriter(forImageCanvas: self))
                    draggingItem.setDraggingFrame(screenshotImageView.frame, contents: draggingImage)
                    beginDraggingSession(with: [draggingItem], event: event, source: self)

Это вызывает метод ниже;

private func pasteboardWriter(forImageCanvas imageCanvas: DragDropContainerView) -> NSPasteboardWriting {
    let provider = FilePromiseProvider(fileType: kUTTypeJPEG as String, delegate: self)
    provider.userInfo = imageCanvas.snapshotItem
    return provider
}

Это устанавливает сеанс пользовательского обещания файла, используя подкласс ниже. Как вы можете видеть, я не рассматриваю здесь какую-либо логику, и кажется, что она делает очень мало или ничего. В качестве дополнительного теста, чтобы убедиться, что он на самом деле ничего не делает, я устанавливаю тип монтажного стола на "аудио". Я перетаскиваю изображение, а не аудио, но оно все еще работает.

public class FilePromiseProvider : NSFilePromiseProvider {
   public override func writableTypes(for pasteboard: NSPasteboard)
    -> [NSPasteboard.PasteboardType] {

        return [kUTTypeAudio as NSPasteboard.PasteboardType]
   }

   public override func writingOptions(forType type: NSPasteboard.PasteboardType,
                                    pasteboard: NSPasteboard)
    -> NSPasteboard.WritingOptions {
        return super.writingOptions(forType: type, pasteboard: pasteboard)
   }
}

До тех пор, пока реализованные выше методы реализованы, он, очевидно, запускает поток, который в конечном итоге вызывает "устаревший" метод ниже. Этот метод прекрасно работает каждый раз в Мохаве, показывая, что должна быть проблема с API NSFilePromises. Если этот метод работает, API-интерфейс файла обещаний должен работать так же, но это не так;

override func namesOfPromisedFilesDropped(atDestination dropDestination: URL) -> [String]?

Как только этот метод вызывается, в Mojave все прекрасно работает для перетаскивания значков приложений в док-станцию ​​и непосредственно в такие приложения, как Evernote, возвращая приложение с функциональностью перетаскивания на 100%, как это было в предыдущих версиях ОС!

Мой файл обещаний делегата все еще на месте, но выглядит так, как показано ниже. Как видите, он больше ничего не делает. Однако это все еще требуется.

extension DragDropContainerView: NSFilePromiseProviderDelegate {
   func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
       return ""
   }

   func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {

   }
}

Любые комментарии по этому "решению" были бы хорошими. Любые предложения о том, как сделать это лучше, также приветствуются. Обратите внимание, что, по словам Apple, "нет гарантии, что файл будет записан вовремя" с использованием API File Promises. Но с учетом вышесказанного, старый устаревший метод так или иначе вызывается в Мохаве и работает безупречно каждый раз.

Спасибо

0 ответов

Другие вопросы по тегам