[英]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.