关于NSTreeController的moveNode:toIndexPath:方法异常问题求助
问题根源
Core Data中声明的NSArray类型属性本质是NSOrderedSet的不可变包装,即使你将其设为读写属性,Core Data默认的属性更新逻辑会忽略指定的插入索引,直接将对象追加到集合末尾。而NSTreeController的moveNode:toIndexPath:方法在操作Core Data实体时,无法通过默认的属性setter触发带索引的插入操作——这就是为什么相同逻辑在NSObject子类上正常,Core Data实体却失效的原因。
具体修复步骤
1. 调整Core Data实体的属性结构
给Folder实体添加一个私有有序关系属性:
- 在Core Data模型编辑器中,新增一个名为
subfolders的关系,目标实体为Folder,设置为有序(Ordered),并勾选“To-Many”。 - 将原有的
subfoldersArray属性改为只读的派生属性,不再直接映射到Core Data存储,而是通过subfolders有序集合生成:
// Folder.h @property (nonatomic, readonly) NSArray *subfoldersArray;
// Folder.m @dynamic subfolders; // 对应Core Data的有序关系 - (NSArray *)subfoldersArray { return self.subfolders.array; }
2. 实现KVC有序集合访问器方法
Core Data依赖KVC访问器方法来识别有序集合的操作,给Folder类添加以下方法,让NSTreeController能正确触发指定索引的插入/删除:
- (void)insertObject:(Folder *)folder inSubfoldersAtIndex:(NSUInteger)index { NSMutableOrderedSet *mutableSubfolders = [self mutableOrderedSetValueForKey:@"subfolders"]; [mutableSubfolders insertObject:folder atIndex:index]; } - (void)removeObjectFromSubfoldersAtIndex:(NSUInteger)index { NSMutableOrderedSet *mutableSubfolders = [self mutableOrderedSetValueForKey:@"subfolders"]; [mutableSubfolders removeObjectAtIndex:index]; } - (void)replaceObjectInSubfoldersAtIndex:(NSUInteger)index withObject:(Folder *)folder { NSMutableOrderedSet *mutableSubfolders = [self mutableOrderedSetValueForKey:@"subfolders"]; [mutableSubfolders replaceObjectAtIndex:index withObject:folder]; }
3. 更新NSTreeController配置
将树控制器的Children键路径从subfoldersArray改为subfolders——Core Data的有序集合(NSOrderedSet)现在可以通过KVC访问器被NSTreeController正确识别,无需再依赖NSArray包装。
验证效果
完成上述修改后,调用NSTreeController的moveNode:toIndexPath:方法时,Core Data会通过你实现的KVC访问器将节点插入到指定索引位置,同时保留NSOutlineView的选中状态(确保树控制器的preservesSelection属性已设为YES)。
这种方案无需直接修改底层模型的集合,完全通过NSTreeController的官方API完成操作,避免了选中状态丢失的问题。
内容的提问来源于stack exchange,提问作者jeanlain

