Должен ли NSFilePromiseProviderDelegate также быть NSView или NSViewController?
Я просматриваю учебник AppKit, поддерживающий перетаскивание файловых обещаний . Я скачал демо-приложение.
Я попытался извлечь функциональность из
ImageCanvasController
класс (который является ) в отдельный класс. (Пожалуйста, смотрите фрагменты кода до и после ниже.)
До моих изменений перетаскивание изображения с холста приложения в Finder и Apple Notes работало нормально. Но после моих изменений ничего не происходит, когда я перетаскиваю в Notes, и я получаю эту ошибку, когда я перетаскиваю в Finder:
2022-02-26 23:16:52.713742+0100 MemeGenerator[31536:1975798] *** CFMessagePort: dropping corrupt reply Mach message (0b000100)
Есть ли какое-либо недокументированное соответствие протоколу, которое мне нужно добавить в новый класс? Или есть какая-то основная логика, для которой
NSFilePromiseProviderDelegate
работает только если это также
NSView
или
NSViewController
? Во всех руководствах, которые я нашел в Интернете, это всегда привязано к представлению, но я не нашел никакого предупреждения, что это должно быть.
Примечание. Причина, по которой я хочу отделить функциональность промис-провайдера от представлений, заключается в том, что таким образом я могу предоставить несколько
NSDraggingItem
возражает против
beginDraggingSession
. Например, когда выбрано несколько элементов и есть
mouseDragged
событие на одном из них, я мог начать сеанс перетаскивания, включая все выбранные элементы.
Код перед
class ImageCanvasController: NSViewController, NSFilePromiseProviderDelegate, ImageCanvasDelegate, NSToolbarDelegate {
...
/// Queue used for reading and writing file promises.
private lazy var workQueue: OperationQueue = {
let providerQueue = OperationQueue()
providerQueue.qualityOfService = .userInitiated
return providerQueue
}()
...
func pasteboardWriter(forImageCanvas imageCanvas: ImageCanvas) -> NSPasteboardWriting {
let provider = NSFilePromiseProvider(fileType: kUTTypeJPEG as String, delegate: self)
provider.userInfo = imageCanvas.snapshotItem
return provider
}
// MARK: - NSFilePromiseProviderDelegate
/// - Tag: ProvideFileName
func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
let droppedFileName = NSLocalizedString("DropFileTitle", comment: "")
return droppedFileName + ".jpg"
}
/// - Tag: ProvideOperationQueue
func operationQueue(for filePromiseProvider: NSFilePromiseProvider) -> OperationQueue {
return workQueue
}
/// - Tag: PerformFileWriting
func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {
do {
if let snapshot = filePromiseProvider.userInfo as? ImageCanvas.SnapshotItem {
try snapshot.jpegRepresentation?.write(to: url)
} else {
throw RuntimeError.unavailableSnapshot
}
completionHandler(nil)
} catch let error {
completionHandler(error)
}
}
}
Код после
class CustomFilePromiseProviderDelegate: NSObject, NSFilePromiseProviderDelegate {
/// Queue used for reading and writing file promises.
private lazy var workQueue: OperationQueue = {
let providerQueue = OperationQueue()
providerQueue.qualityOfService = .userInitiated
return providerQueue
}()
/// - Tag: ProvideFileName
func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, fileNameForType fileType: String) -> String {
let droppedFileName = NSLocalizedString("DropFileTitle", comment: "")
return droppedFileName + ".jpg"
}
/// - Tag: ProvideOperationQueue
func operationQueue(for filePromiseProvider: NSFilePromiseProvider) -> OperationQueue {
return workQueue
}
/// - Tag: PerformFileWriting
func filePromiseProvider(_ filePromiseProvider: NSFilePromiseProvider, writePromiseTo url: URL, completionHandler: @escaping (Error?) -> Void) {
do {
if let snapshot = filePromiseProvider.userInfo as? ImageCanvas.SnapshotItem {
try snapshot.jpegRepresentation?.write(to: url)
} else {
throw RuntimeError.unavailableSnapshot
}
completionHandler(nil)
} catch let error {
completionHandler(error)
}
}
}
class ImageCanvasController: NSViewController, ImageCanvasDelegate, NSToolbarDelegate {
...
func pasteboardWriter(forImageCanvas imageCanvas: ImageCanvas) -> NSPasteboardWriting {
let delegate = CustomFilePromiseProviderDelegate()
let provider = NSFilePromiseProvider(fileType: kUTTypeJPEG as String, delegate: delegate)
provider.userInfo = imageCanvas.snapshotItem
return provider
}
}
1 ответ
Должен ли NSFilePromiseProviderDelegate также быть NSView или NSViewController?
Нет.
delegate
является локальной переменной и освобождается в конце
pasteboardWriter(forImageCanvas:)
. Без делегата поставщик файловых обещаний не работает. Решение: сохраните сильную ссылку на делегата.
class ImageCanvasController: NSViewController, ImageCanvasDelegate, NSToolbarDelegate {
let delegate = CustomFilePromiseProviderDelegate()
...
func pasteboardWriter(forImageCanvas imageCanvas: ImageCanvas) -> NSPasteboardWriting {
let provider = NSFilePromiseProvider(fileType: kUTTypeJPEG as String, delegate: delegate)
provider.userInfo = imageCanvas.snapshotItem
return provider
}
}