Мои самые ранние шаги в разработке OS X.NSTreeview Дублирование моих объектов
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, расположенныхОбъектов, есть только ожидаемое количество элементов. Никаких дубликатов на самом деле не существует, так где же дубликаты в 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
------------ UPDATE ---------
Итак, я изменил от 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"];
}
}
Наблюдатели дважды уведомляются с помощью 'willChangeValueForKey: @" children "и' mutableArrayValueForKey'? – Willeke
Я слежу за перерывами, и, похоже, вы можете что-то сказать. Если вы раскроете комментарий, в качестве ответа с предложениями, я с радостью сделаю это правильно. –