NSTableView и перетаскивание из Finder

Я пытаюсь реализовать перетаскивание из Finder в NSTableView моего приложения. В настройке используется NSTableView, контроллер массива, который действует как источник данных, используя привязки Cocoa к хранилищу основных данных.

Я сделал следующее, в основном следуя различным сообщениям в блоге, которые я нашел на SO и других сайтах:

В awakeFromNib моего контроллера просмотра я вызываю:

[[self sourcesTableView] registerForDraggedTypes:[NSArray arrayWithObjects: NSPasteboardTypePNG, nil]];

Я подклассифицировал NSArrayController и добавил к моему подклассу следующие методы (аргументация для подкласса заключается в том, что диспетчер массива должен быть проинформирован о падении, поскольку он действует как источник данных в представлении таблицы):

- (BOOL) tableView: (NSTableView *) aTableView acceptDrop: (id < NSDraggingInfo >) info row: (NSInteger) row dropOperation: (NSTableViewDropOperation)operation

Моя реализация для вышеперечисленного в настоящее время только записывает в журнал, а затем возвращает логическое значение YES.

- (NSDragOperation) tableView: (NSTableView *) aTableView validateDrop: (id < NSDraggingInfo >) info proposedRow: (NSInteger) row proposedDropOperation: (NSTableViewDropOperation) operation

В IB у меня есть контроллер массива, указывающий на мой пользовательский подкласс NSArrayController.

Результат: ничего. Когда я перетаскиваю PNG с рабочего стола на мой табличный вид, ничего не происходит, и файл с радостью отскакивает назад. Я должен делать что-то неправильно, но не понимаю, что. Где я ошибаюсь?

Ответ 1

Перетаскивание из Finder всегда является перетаскиванием файла, а не перетаскиванием изображения. Вам нужно будет поддерживать перетаскивание URL-адресов из Finder.

Чтобы сделать это, вам нужно объявить, что вам нужны типы URL:

[[self sourcesTableView] registerForDraggedTypes:[NSArray arrayWithObject:(NSString*)kUTTypeFileURL]];

Вы можете проверить файлы следующим образом:

 - (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id < NSDraggingInfo >)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation
{
    //get the file URLs from the pasteboard
    NSPasteboard* pb = info.draggingPasteboard;

    //list the file type UTIs we want to accept
    NSArray* acceptedTypes = [NSArray arrayWithObject:(NSString*)kUTTypeImage];

    NSArray* urls = [pb readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]]
     options:[NSDictionary dictionaryWithObjectsAndKeys:
                [NSNumber numberWithBool:YES],NSPasteboardURLReadingFileURLsOnlyKey,
                acceptedTypes, NSPasteboardURLReadingContentsConformToTypesKey,
                nil]];

    //only allow drag if there is exactly one file
    if(urls.count != 1)
        return NSDragOperationNone;

    return NSDragOperationCopy;
}

Затем вам нужно будет снова извлечь URL-адрес при вызове метода tableView:acceptDrop:row:dropOperation:, создать образ из URL-адреса и затем сделать что-то с этим изображением.

Даже если вы используете привязки Cocoa, вам все равно нужно назначить и реализовать объект как datasource вашего NSTableView, если вы хотите использовать методы перетаскивания. Подклассификация NSTableView не принесет пользы, поскольку методы источника данных не реализованы в NSTableView.

Вам нужно только реализовать связанные с перетаскиванием методы в объекте источника данных, а не те, которые предоставляют данные таблицы, когда вы используете привязки для этого. Это ваша обязанность уведомить контроллер массива о результате падения, вызвав один из методов NSArrayController, например insertObject:atArrangedObjectIndex:, или путем изменения массива подкачки с использованием методов доступа, соответствующих стандарту Key-Value Coding.