filePromiseProvider writePromiseTo URL не работает при перетаскивании изображения в другое приложение - PullRequest
3 голосов
/ 07 марта 2019

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

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

I 'Мы пытались сделать это, используя полные 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.Но с учетом вышесказанного, старый устаревший метод каким-то образом вызывается в Мохаве и работает каждый раз безупречно.

Спасибо

...