2016-02-14 3 views
0

Мои самые ранние шаги в разработке OS X.NSTreeview Дублирование моих объектов

NSTreeview привязан к массиву, который включает в себя различные прокси-объекты пользовательского класса. Некоторые из этих объектов привязаны к моему основному хранилищу данных, так что моя боковая панель включает в себя списки из нескольких разных объектов NSManagedObject в группах. По какой-то причине объекты moc дублируются, каждый из которых указан дважды. как так:

Groups bound to NSManangedObjects are repeated in list

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"]; 
    } 
} 
+0

Наблюдатели дважды уведомляются с помощью 'willChangeValueForKey: @" children "и' mutableArrayValueForKey'? – Willeke

+0

Я слежу за перерывами, и, похоже, вы можете что-то сказать. Если вы раскроете комментарий, в качестве ответа с предложениями, я с радостью сделаю это правильно. –

ответ

0

дублированные элементы, вероятно, вызваны уведомлениями дублированных изменений. didChangeValueForKey:@"children" и mutableArrayValueForKey оба уведомляют наблюдателя. Это путает контроллер дерева. Используйте либо комбинацию willChangeValueForKeydidChangeValueForKey, либо используйте mutableArrayValueForKey.

observeValueForKeyPath можно назвать несколько раз. arrangedObjects из NSArrayController изменяется, когда объект добавляется или удаляется, когда содержимое сортируется и всякий раз, когда NSArrayController считает, что arrangedObjects необходимо изменить.

+0

Кажется, что это точно так, и теперь у меня есть работа, когда я обновляюсь в вопросе. Одна вещь, я сначала попытался исключить willChangeValueForKey и didChangeValueForKey, оставляя mutableArrayValueForKey. В этом случае у меня все еще были обманы. –

Смежные вопросы