0

这是我上一个问题的后续问题,与为什么我的managedObjectContext返回为零有关。我认为问题的方向会被埋在旧问题中。

我现在让我的mangedObjectContext不返回 nil,并且在执行[outlineView reloadData]时,我的 outlineView 什么也没有发生。我尝试有选择地删除旨在更新大纲视图的部分代码,以查看是否有任何变化,答案是否定的。从那以后,我发现(在我最初写了这个问题之后)我的 dataSource 关联在某个阶段正在消失。

笔记:

  • 下面包含的代码在数据源类的 awakeFromNib 上运行一次,并且运行良好。
  • 我的问题出现在任何其他时间调用它。我没有调试错误,但我的 outlineView 保持不变。
  • 我将其缩小到在 NSLog 上运行[outlineView dataSource]。当从中调用该方法时,awakeFromNib它会将 dataSource 作为我的 dataSourceClass 正确返回。每隔一次,它将 dataSource 返回为nil
  • dataSourceClass 绑定到InterfaceBuilder中的 outlineView 。
  • 我对代码数组中的对象更新所做的所有其他 NSLog 检查都按预期返回,并且更新正确。事实上,我检查了最终的projectsArrayclientsArray,它们包含在试图在 outlineView 中创建节点之前引入的所有新对象。
  • 我正在使用标准的 xcode 生成的核心数据应用程序委托代码。
  • 我没有使用NSTreeController和使用我自己的NSOutlineViewDataSource. 如何根据两个核心数据实体的父/子关系填充大纲视图是不可能的(或没有记录)。
  • 我还将NSOutlineViewDataSource在下面包含我的代码。

更新:

更新 1: 嗯...就在我打电话之前,[outlineView reloadData]我尝试了一个NSLogfor[outlineView dataSource]并且它返回为nil。我最初通过interfaceBuilder中的绑定将dataSource与 outlineView相关联。我现在假设这是我的问题。为什么我的数据源会被释放?如果我不能阻止它被释放,我该如何取回它?

代码:

刷新OutLineView:

rootNode = [[IFParentNode alloc] initWithTitle:@"Root" children:nil];
    NSInteger clientCounter;
    clientCounter = 0;
    NSFetchRequest *clientsFetchRequest = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *clientsMoc = [clientsController managedObjectContext];
    NSLog(@"clientsMoc is : %@", clientsMoc);
    if(clientsMoc == nil) {
        NSLog(@"And, yes, clientsMoc is = nil");
        clientsMoc = [(Voiced_AppDelegate *)[[NSApplication sharedApplication] delegate] managedObjectContext]; 
        NSLog(@"After managedObjectContext: %@",  clientsMoc);
    }
    NSEntityDescription *clientsEntity = [NSEntityDescription entityForName:@"Clients" inManagedObjectContext:clientsMoc];
    //NSLog(@"clientsEntity, after the 'if nil' code is now: %@", clientsEntity);
    [clientsFetchRequest setEntity:clientsEntity];
    //sort
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"clientCompany" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [clientsFetchRequest setSortDescriptors:sortDescriptors];
    NSError *clientsFetchError = nil;
    clientsArray = [clientsMoc executeFetchRequest:clientsFetchRequest error:&clientsFetchError];
    [clientsFetchRequest release];
    //NSLog(@"clientsArray, after fetching is now: %@", clientsArray);

    NSInteger projectCounter;
    projectCounter = 0;
    NSFetchRequest *projectsFetchRequest = [[NSFetchRequest alloc] init];
    NSManagedObjectContext *projectsMoc= [projectsController managedObjectContext];
    if(projectsMoc == nil) {
        NSLog(@"And, yes, projectsMoc is = nil");
        projectsMoc = [(Voiced_AppDelegate *)[[NSApplication sharedApplication] delegate] managedObjectContext]; 
        NSLog(@"After managedObjectContext: %@",  projectsMoc);
    }
    NSEntityDescription *projectsEntity = [NSEntityDescription entityForName:@"Projects" inManagedObjectContext:projectsMoc];
    [projectsFetchRequest setEntity:projectsEntity];
    NSError *projectsFetchError = nil;
    projectsArray = [projectsMoc executeFetchRequest:projectsFetchRequest error:&projectsFetchError];
    [projectsFetchRequest release];
    //NSLog(@"projectsArray, after fetching is now: %@", projectsArray);

    for (NSString *s in clientsArray) {
        NSManagedObject *clientMo = [clientsArray objectAtIndex:clientCounter];  // assuming that array is not empty
        id clientValue = [clientMo valueForKey:@"clientCompany"];
        //NSLog(@"Company is %@", parentValue);

        IFParentNode *tempNode = [[IFParentNode alloc] initWithTitle:[NSString stringWithFormat:@"%@", clientValue] children:nil];

        clientCounter = clientCounter + 1;
        [rootNode addChild:tempNode];
        [tempNode release];
    }

    for (NSString *s in projectsArray) {
        NSInteger viewNodeIndex;
        viewNodeIndex = 0;
        NSManagedObject *projectMo = [projectsArray objectAtIndex:projectCounter];  // assuming that array is not empty
        id projectValue = [projectMo valueForKey:@"projectTitle"];
        id projectParent = [[projectMo valueForKey:@"projectParent"] valueForKey: @"clientCompany"];
        // find if theres an item with the projetParent name
        id nodeTitle = [[rootNode children] valueForKey:@"title"];
        for(NSString *companies in nodeTitle) {
            if([companies compare:projectParent] == NSOrderedSame) {
                //NSLog(@"Company is %@ and parent is %@ and id is: %d", companies, projectParent, viewNodeIndex);
                // then assign that node to be the tempnode.
                IFParentNode *tempNode = [rootNode.children objectAtIndex:viewNodeIndex];
                IFChildNode *subTempNode = [[IFChildNode alloc] initWithTitle:[NSString stringWithFormat:@"%@", projectValue]];
                [tempNode addChild:subTempNode];
                [subTempNode release];
                [tempNode release];
            } else {
                // do nothing.
            }
            viewNodeIndex = viewNodeIndex + 1;
        }
        projectCounter = projectCounter + 1;
    }
    [outlineView expandItem:nil expandChildren:YES];
    [outlineView reloadData];
}

大纲视图数据源:

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
    if([item isKindOfClass:[IFChildNode class]]) {
        return nil;
    }
    return (item == nil ? [rootNode childAtIndex:index] : [(IFParentNode *)item childAtIndex:index]);
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
    return (item == nil || [item isKindOfClass:[IFParentNode class]]);
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
    if([item isKindOfClass:[IFChildNode class]]) {
        return 0;
    }

    return (item == nil ? [rootNode numberOfChildren] : [(IFParentNode *)item numberOfChildren]);
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
    if([item isKindOfClass:[IFChildNode class]]) {
        return ((IFChildNode *)item).title;
    }

    if([item isKindOfClass:[IFParentNode class]]) {
        return ((IFParentNode *)item).title;
    }

    return nil;
}

// Unessential methods for datasource

- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
    return (item == nil || [item isKindOfClass:[IFParentNode class]]);
}

- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item {
    return ([item isKindOfClass:[IFChildNode class]]);
}

/* - - - - - - - - - - - - - - - - - - - -
IfChild
 - - - - - - - - - - - - - - - - - - - - */

@implementation IFChildNode
@synthesize title;
- (id)initWithTitle:(NSString *)theTitle {
    if(self = [super init]) {
        self.title = theTitle;
    }

    return self;
}

- (void)dealloc {
    self.title = nil;
    [super dealloc];
}
@end

/* - - - - - - - - - - - - - - - - - - - -
IfParent
 - - - - - - - - - - - - - - - - - - - - */

@implementation IFParentNode
@synthesize title, children;
- (id)initWithTitle:(NSString *)theTitle children:(NSMutableArray *)theChildren {
    if(self = [super init]) {
        self.title = theTitle;
        self.children = (theChildren == nil ? [NSMutableArray new] : theChildren);
    }

    return self;
}

- (void)addChild:(id)theChild {
    [self.children addObject:theChild];
}

- (void)insertChild:(id)theChild atIndex:(NSUInteger)theIndex {
    [self.children insertObject:theChild atIndex:theIndex];
}

- (void)removeChild:(id)theChild {
    [self.children removeObject:theChild];
}

- (NSInteger)numberOfChildren {
    return [self.children count];
}

- (id)childAtIndex:(NSUInteger)theIndex {
    return [self.children objectAtIndex:theIndex];
}

- (void)dealloc {
    self.title = nil;
    self.children = nil;
    [super dealloc];
}
4

2 回答 2

1

大多数情况下,这意味着您无意中创建了类的两个实例。一个在你的笔尖中并连接到所有东西,而另一个要么在代码中创建,要么在笔尖的其他地方创建,没有任何连接。证明这种情况发生的一个简单方法是同时登录selfawakeFromNib一些看到 nil 的方法——你会看到两个对象的不同地址。你还会发现它outlineView本身是 nil,因为插座没有连接任何东西。

于 2011-03-15T20:23:54.740 回答
0

在我看来,您正在对控制器中的数据而不是数据模型中的数据强加树结构。您不必将两个实体提取到两个数组中,然后将它们硬塞在一起来创建您的树。绑定背后的想法是控制器简单地将数据模型链接到控件,并且控件在数据模型中显示对象图。

所以,我认为您需要备份并再次查看您的数据模型。我推断你需要一个像这样的数据模型:

Client{
    name:string
    //... some other attributes
    projects<-->>Project.client
}

Project:
    name:string
    // ... some other attributes
    client<<-->Client.projects
}

您需要一个将客户及其相关项目对象显示为子对象的大纲。

如果您使用 NSTreeController ,您会将树控制器绑定到具有子路径的实体 Clientprojects

如果您使用大纲数据源,您只需获取按您希望排序的客户端对象,然后根据需要返回它们和它们的项目。

这里重要的是大纲或树形结构应该是数据模型本身固有的。如果不是,那么您可能不希望用户以大纲形式查看和思考数据。

还要记住,数据模型是模型-视图-控制器设计的整个层,而不仅仅是一个愚蠢的比特存储。它可以并且应该包含在应用程序中表示活动数据所需的所有逻辑。可以说,数据模型是应用程序的核心,根据需要添加 UI、网络或持久性。不要害怕将与数据相关的逻辑放在数据模型中。

于 2011-03-15T20:57:30.703 回答