簡體   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