我需要在我的应用程序的两个表视图之间拖动对 NSManagedObject 的引用。存储对 NSManagedObject 的引用的首选 NSPasteboard 类型是什么?
我当前的解决方案是将对象的 NSManagedObjectID 的 URIRepresentation 存储在 NSPasteboardTypeString 中。我怀疑那里有一个更优雅的解决方案。
我需要在我的应用程序的两个表视图之间拖动对 NSManagedObject 的引用。存储对 NSManagedObject 的引用的首选 NSPasteboard 类型是什么?
我当前的解决方案是将对象的 NSManagedObjectID 的 URIRepresentation 存储在 NSPasteboardTypeString 中。我怀疑那里有一个更优雅的解决方案。
所有模型对象都没有标准类型,因为您的模型对象及其处理方式对于您的应用程序来说是独一无二的。如果所有人都有一种粘贴板类型,那么就无法区分它们了。您自己的自定义对象应该有自己的拖动类型。
只需使用一个有意义的字符串(可能是#define,以便您可以在 Xcode 中通过自动完成功能找到它),例如解析为“com.yourcompany.yourapp.yourobjecttype”的“MyObjectPboardType”。
使用 NSPasteboard 的 -declareTypes:owner: 来声明您的新类型,然后使用 -setString:forType: 或其他 -set?:forType: 方法之一来设置对象类型的信息。在您的情况下,对象 ID 的使用是完全可以接受的标识符。请记住,托管对象的对象 ID 在它们是新对象和持久对象时会发生变化。
如果您在同一个应用程序中的表格中拖动,则不妨将 tableView (outlineView) 中对象的 rowIndexes (indexPaths,如果您从 outlineView 拖动) 放入粘贴板。如果 tableViews 的数据源是 NSArrayController(outlineView 的 NSTreeController),这也可以让你免于一些不需要的 CoreData 访问。然后,您可以在接受 drop 时轻松检索拖动的对象,因为传递给两个方法 'tableView:validateDrop:proposedRow:proposedDropOperation:' 和 'tableView:acceptDrop:row:dropOperation:' 的 'info' 对象将引用tableView 在“draggingSource”键路径下发起拖动。
这是一个简单的实现:
extern NSString *const kMyLocalDragType = @"com.whatever.localDragType";
@implementation MyArrayControllerDataSource
.
.
.
#pragma mark - NSTableViewDataSource (Drag & Drop)
+ (NSArray *)dragTypes {
// convenience method returning all class's supported dragTypes
return @[kMyLocalDragType];
}
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard {
[pboard declareTypes:[[self class] dragTypes] owner:self];
for (NSString *aDragType in [[self class] dragTypes]) {
if (aDragType == kMyLocalDragType) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes]; // we are supporting drag&drop of multiple items selected
[pboard setData:data forType:aDragType];
}
.
. // logic for other dragTypes
.
}
return YES;
}
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
NSArray *dragTypes = [info draggingPasteboard] types];
for (id aDragType in dragTypes) {
if (aDragType == kMyLocalDragType) {
return NSDragOperationCopy;
}
}
.
.// Other logic for accepting drops/affect drop operation
.
}
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
if ([info draggingPasteboard] types] containsObject:kMyLocalDragType]) {
// Retrieve the index set from the pasteboard:
NSData *data = [[info draggingPasteboard] dataForType:kMyLocalDragType];
NSIndexSet *rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSArray *droppedObjects = [self retrieveFromTableView:tableView objectsAtRows:rowIndexes];
// droppedObjects contains dragged and dropped objects, do what you
// need to do with them, then add them to this dataSource:
[self.content insertObjects:droppedObjects];
[tableView reloadData];
[tableView deselectAll:nil];
return YES;
}
.
. // other logic for accepting drops of other dragTypes supported.
.
}
#pragma mark - Helpers
- (NSArray <NSManagedObject *> *)retrieveFromTableView:(NSTableView *)tableView objectsAtRowIndexes:(NSIndexSet *)rowIndexes {
id dataSource = [tableView dataSource];
if ([dataSource respondsToSelector:@selector(content)]) {
if ([dataSource.content respondsToSelector:@selector(objectsAtIndexes:)]) {
return [datasource content] objectsAtIndexes:rowIndexes];
}
}
return @[]; //We return an empty array in case introspection check failed
}