简体   繁体   English

NSTreeview复制我的对象

[英]NSTreeview Duplicating my objects

My very early steps in OS X development. 我在OS X开发中的早期步骤。

NSTreeview bound to an array which includes various proxy objects of custom class. NSTreeview绑定到一个数组,该数组包括自定义类的各种代理对象。 Some of those objects are bound to my Core Data Store so that my sidebar includes lists of several different NSManagedObject entities in groups. 这些对象中的一些已绑定到我的核心数据存储,因此我的侧边栏包含成组的几个不同NSManagedObject实体的列表。 For some reason the moc entities are duplicated, each listed twice. 由于某种原因,moc实体重复,每个实体列出两次。 like so: 像这样:

绑定到NSManangedObjects的组在列表中重复

NSTreeController is bound to NSArray, sidebarItems, which is populated here: 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
}

In viewDidLoad I set up the Core Data bindings and NSArrayControllers for each group: 在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]];

The actual controllers are setup here: 实际的控制器在这里设置:

-(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;
}

I checked the state of my NSArrayControllers, arrangedObjects, there are only the expected number of items there. 我检查了我的NSArrayControllers,organizedObjects的状态,那里只有预期的项目数。 No duplicates actually exist so where are the duplicates in the OutlineView coming from? 实际上没有重复项,因此OutlineView中的重复项来自哪里?

My proxy object, in case it helps: 我的代理对象,以防万一:

#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--------- ------------更新---------

So, I changed from the NSMutableArrayForKey to creating a new NSMutableArray and replacing the children array when my objects are all set up. 因此,我从NSMutableArrayForKey更改为创建新的NSMutableArray并在所有对象都设置好后替换了children数组。 This eliminated the duplicate list however, There is still something afoul. 这消除了重复的列表,但是,仍然存在一些问题。 I put some debug statements and counters in there and I can see that the routine is run 3 or 4 times on each of these groups. 我在其中放置了一些调试语句和计数器,可以看到例程在每个组上运行了3或4次。 That seems unnecessary. 似乎没有必要。 I suppose it is not making duplicates because the previous results are now replaced by the latest run. 我想它不会重复,因为以前的结果现在被最新的运行所代替。 Still would like to solve rather than leave as it is. 还是想解决而不是保持现状。

This is revised observer: 这是经修订的观察员:

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

The duplicated items are probably caused by duplicate change notifications. 重复的项目可能是由重复的更改通知引起的。 didChangeValueForKey:@"children" and mutableArrayValueForKey both notify the observer. didChangeValueForKey:@"children"mutableArrayValueForKey都通知观察者。 This will confuse the tree controller. 这会混淆树控制器。 Either use the willChangeValueForKey didChangeValueForKey combo or use mutableArrayValueForKey . 要么使用willChangeValueForKey didChangeValueForKey组合,要么使用mutableArrayValueForKey

observeValueForKeyPath can be called multiple times. observeValueForKeyPath可以多次调用。 arrangedObjects of NSArrayController changes when an object is added or removed, when the contents is sorted and whenever NSArrayController thinks arrangedObjects has to be changed. arrangedObjectsNSArrayController当对象被添加或删除,当内容被分类和每当改变NSArrayController认为arrangedObjects必须被改变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM