[英]How to update values of objects in NSMutableDictionary without duplicating the item
[英]NSTreeview Duplicating my objects
我在OS X开发中的早期步骤。
NSTreeview绑定到一个数组,该数组包括自定义类的各种代理对象。 这些对象中的一些已绑定到我的核心数据存储,因此我的侧边栏包含成组的几个不同NSManagedObject
实体的列表。 由于某种原因,moc实体重复,每个实体列出两次。 像这样:
NSTreeController绑定到NSArray sidebarItems,此处填充:
- (void)populateOutlineContents
{
// hide the outline view - don't show it as we are building the content
[self.myOutlineView setHidden:YES];
BrowserItem *dashboardItem = [BrowserItem itemWithTitle:@"Home"];
dashboardItem.nodeIcon = [NSImage imageNamed:@"home"];
BrowserItem *todayItem = [BrowserItem itemWithTitle:@"Today"];
BrowserItem *thisWeekItem = [BrowserItem itemWithTitle:@"This Week"];
BrowserItem *separatorItem = [BrowserItem itemWithTitle:nil];
// Setup Projects
self.projectsSidebarGroup = [BrowserItem itemWithTitle:PROJECTS_NAME];
self.projectsSidebarGroup.childItemTitleKeypath = @"projectName";
[self.projectsSidebarGroup bindChildItemsToArrayKeypath:@"projectsArrayController.arrangedObjects" onObject:self];
// Setup Crewmen
self.crewmenSidebarGroup = [BrowserItem itemWithTitle:CREWMEN_NAME];
self.crewmenSidebarGroup.childItemTitleKeypath = @"fullName";
[self.crewmenSidebarGroup bindChildItemsToArrayKeypath:@"crewmenArrayController.arrangedObjects" onObject:self];
self.sidebarItems = @[dashboardItem, todayItem, thisWeekItem,separatorItem, self.projectsSidebarGroup, self.crewmenSidebarGroup];
[self.myOutlineView setHidden:NO]; // we are done populating the outline view content, show it again
}
在viewDidLoad中,我为每个组设置核心数据绑定和NSArrayControllers:
[self populateOutlineContents];
NSPredicate *ActiveProjectsFilter = [NSPredicate predicateWithFormat:@"inactive == NO"];
NSSortDescriptor *sortByName = [[NSSortDescriptor alloc] initWithKey:@"projectName" ascending:YES];
self.projectsArrayController = [self controllerForEntity:@"Project" filter:ActiveProjectsFilter sortBy:@[sortByName]];
NSPredicate *activeCrewmenFilter = [NSPredicate predicateWithFormat:@"Active == YES"];
NSSortDescriptor *sortByLast = [[NSSortDescriptor alloc] initWithKey:@"nameLast" ascending:YES];
NSSortDescriptor *sortByFirts = [[NSSortDescriptor alloc] initWithKey:@"nameFirst" ascending:YES];
self.crewmenArrayController = [self controllerForEntity:@"WorkMan" filter:activeCrewmenFilter sortBy:@[sortByLast, sortByFirts]];
实际的控制器在这里设置:
-(NSArrayController *)controllerForEntity:(NSString *)aEntityName filter:(NSPredicate *)filter sortBy:(NSArray *)sortDescriptors
{
NSArrayController *controller = [[NSArrayController alloc] init];
controller.managedObjectContext = self.managedObjectContext;
controller.entityName = aEntityName;
controller.automaticallyRearrangesObjects = YES;
controller.automaticallyPreparesContent = YES;
if (filter) {
controller.fetchPredicate = filter;
}
if (sortDescriptors) {
controller.sortDescriptors = sortDescriptors;
}
NSError *error;
if (![controller fetchWithRequest:nil merge:NO error:&error])
{
ALog(@"Error fetching %@", aEntityName);
}
return controller;
}
我检查了我的NSArrayControllers,organizedObjects的状态,那里只有预期的项目数。 实际上没有重复项,因此OutlineView中的重复项来自哪里?
我的代理对象,以防万一:
#import "BrowserItem.h"
@implementation BrowserItem
+(instancetype)itemWithTitle:(NSString *)title
{
BrowserItem *item = [[BrowserItem alloc] init];
[item setTitle:title];
return item;
}
- (instancetype)init
{
if (self = [super init])
{
self.children = [NSMutableArray array];
self.modelToItemMapping = [NSMapTable weakToStrongObjectsMapTable];
self.childItemsArrayController = [[NSArrayController alloc] init];
[self.childItemsArrayController addObserver:self forKeyPath:@"arrangedObjects" options:NSKeyValueObservingOptionPrior context:NULL];
}
return self;
}
- (void)bindChildItemsToArrayKeypath:(NSString*)keypath onObject:(id)object;
{
[self.childItemsArrayController bind:@"contentArray" toObject:object withKeyPath:keypath options:nil];
self.isGroup = YES;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"arrangedObjects"])
{
[self willChangeValueForKey:@"children"];
NSMutableArray *watchableChildren = [self mutableArrayValueForKey:@"children"];
[watchableChildren removeAllObjects];
for (id modelItem in self.childItemsArrayController.arrangedObjects)
{
BrowserItem *browserItem = [self.modelToItemMapping objectForKey:modelItem];
if (!browserItem)
{
browserItem = [BrowserItem itemWithTitle:[modelItem valueForKey:self.childItemTitleKeypath]];
[self.modelToItemMapping setObject:browserItem forKey:modelItem];
}
[watchableChildren addObject:browserItem];
}
[self didChangeValueForKey:@"children"];
}
}
@end
------------更新---------
因此,我从NSMutableArrayForKey
更改为创建新的NSMutableArray
并在所有对象都设置好后替换了children数组。 这消除了重复的列表,但是,仍然存在一些问题。 我在其中放置了一些调试语句和计数器,可以看到例程在每个组上运行了3或4次。 似乎没有必要。 我想它不会重复,因为以前的结果现在被最新的运行所代替。 还是想解决而不是保持现状。
这是经修订的观察员:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"arrangedObjects"])
{
[self willChangeValueForKey:@"children"];
NSMutableArray *replacementChildren = [NSMutableArray array];
for (id modelItem in self.childItemsArrayController.arrangedObjects)
{
BrowserItem *browserItem = [self.modelToItemMapping objectForKey:modelItem];
if (!browserItem)
{
browserItem = [BrowserItem itemWithTitle:[modelItem valueForKey:self.childItemTitleKeypath]];
[self.modelToItemMapping setObject:browserItem forKey:modelItem];
[self.itemToModelMapping setObject:modelItem forKey:browserItem];
}
[replacementChildren addObject:browserItem];
}
_children = replacementChildren;
[self didChangeValueForKey:@"children"];
}
}
重复的项目可能是由重复的更改通知引起的。 didChangeValueForKey:@"children"
和mutableArrayValueForKey
都通知观察者。 这会混淆树控制器。 要么使用willChangeValueForKey
didChangeValueForKey
组合,要么使用mutableArrayValueForKey
。
observeValueForKeyPath
可以多次调用。 arrangedObjects
的NSArrayController
当对象被添加或删除,当内容被分类和每当改变NSArrayController
认为arrangedObjects
必须被改变。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.