繁体   English   中英

NSTreeview复制我的对象

[英]NSTreeview Duplicating my objects

我在OS X开发中的早期步骤。

NSTreeview绑定到一个数组,该数组包括自定义类的各种代理对象。 这些对象中的一些已绑定到我的核心数据存储,因此我的侧边栏包含成组的几个不同NSManagedObject实体的列表。 由于某种原因,moc实体重复,每个实体列出两次。 像这样:

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

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可以多次调用。 arrangedObjectsNSArrayController当对象被添加或删除,当内容被分类和每当改变NSArrayController认为arrangedObjects必须被改变。

暂无
暂无

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

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