URL saveAs extension - PullRequest
       32

URL saveAs extension

0 голосов
/ 17 марта 2020

Когда это расширение URL запускается как панель, оно не может вернуть URL, по-видимому, в обход завершения:

func saveAs() -> URL? {
    let savePanel = NSSavePanel()
    var saveAsURL : URL? = nil

    savePanel.canCreateDirectories = true
    savePanel.nameFieldStringValue = self.lastPathComponent
    savePanel.directoryURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!

    if let keyWindow = NSApp.keyWindow {
        savePanel.beginSheetModal(for: keyWindow, completionHandler: { result in
            /*if result == .OK {*/ saveAsURL = savePanel.url //}
        })
    }
    else
    {
        NSApp.activate(ignoringOtherApps: true)

        if savePanel.runModal() == .OK {
            saveAsURL = savePanel.url
        }
    }
    Swift.print("saveAsURL => \(saveAsURL.debugDescription)")

    return saveAsURL
}

, но работает как отдельное окно, оно работает нормально. Есть другой связанный ответ здесь , но здесь использование отличается: т.е.

guard let saveAsURL = URL.init(string: "download.dmg").saveAs() else { return }

, где я предполагаю, что пользователь отменяет вывод, что обработка должна закончиться.

Ответы [ 2 ]

0 голосов
/ 18 марта 2020

Что я придумал после моего предложения re: обработчик завершения.

func saveAs(responseHandler: @escaping (URL?) -> Void) {
    let savePanel = NSSavePanel()

    savePanel.canCreateDirectories = true
    savePanel.nameFieldStringValue = self.lastPathComponent
    savePanel.directoryURL = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!

    if let keyWindow = NSApp.keyWindow {
        savePanel.beginSheetModal(for: keyWindow, completionHandler: { result in
            responseHandler( result == .OK ? savePanel.url : nil )
         })
    }
    else
    {
        NSApp.activate(ignoringOtherApps: true)

        let result = savePanel.runModal()
        responseHandler( result == .OK ? savePanel.url : nil )
    }
}

и назвал так - ответный делегат; пользователь щелкнул ссылку на скачивание (двоичного) файла данных, известного по его UTI, поэтому мы загружаем, а затем возвращаемся к более раннему URL:

    guard url.hasDataContent(), let suggestion = response.suggestedFilename else { decisionHandler(.allow); return }
    let downloadDir = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first!
    let saveURL = downloadDir.appendingPathComponent(suggestion)
    saveURL.saveAs(responseHandler: { saveAsURL in
        if let saveAsURL = saveAsURL {
            self.loadFileAsync(url, to: saveAsURL, completion: { (path, error) in
                if let error = error {
                    NSApp.presentError(error)
                }
                else
                {
                    if appDelegate.isSandboxed() { _ = appDelegate.storeBookmark(url: saveAsURL, options: [.withSecurityScope]) }
                }
            })
        }

        decisionHandler(.cancel)
        self.backPress(self)
     })

Я думаю, что мне больше нравится старый способ; - )

0 голосов
/ 17 марта 2020

Когда вы говорите .runModal, ваш код делает очень, очень странную вещь: он останавливает и ждет, когда пользователь решит модальный диалог (также известный как blocking ) , Это восходит к чрезвычайно ранним временам OS X / Cocoa и является аномалией в поведении. Таким образом, в результате мы получаем к концу метода и к вашим Swift.print и return, мы вернулись из модального диалога, и у нас есть значение из него.

Но, как я уже сказал, это совершенно странно. (На самом деле, я не уверен, что могу думать о любом другом вызове Какао, который действует подобным образом.) Вызов .beginSheetModal ведет себя нормально, то есть после вызова ваш код продолжается и завершается с помощью print и return до модальный лист даже может появиться. То, что происходит внутри модального листа, затем происходит асинхронно в отношении вызывающего кода здесь - то есть позже . Таким образом, вы не можете вернуть значение из диалога, потому что вам понадобится машина времени, чтобы заглянуть в будущее. Это стандартный шаблон для такого рода вещей.

...