为什么我的NSOutlineView数据源为零? [英] Why is my NSOutlineView datasource nil?

查看:99
本文介绍了为什么我的NSOutlineView数据源为零?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我上一个问题的后续问题,涉及为什么我的 managedObjectContext 返回零.我认为问题的方向将被埋在旧的问题中.

This is a follow-on question from my previous one relating to why my managedObjectContext was returning to nil. I thought the direction of the question would get buried in the old one.

我现在使我的 mangedObjectContext 不返回nil,并且在执行[outlineView reloadData]时,我的outlineView丝毫不动.我尝试有选择地删除旨在更新 outlineView 的代码部分,以查看是否有任何更改,并且答案是否定的.从那以后,我发现(最初写了这个问题之后)我的dataSource关联在某个阶段消失了.

I now get my mangedObjectContext to not return nil and when performing [outlineView reloadData], nothing at all happens to my outlineView. I tried selectively removing parts of the code that are intended to update the outlineView to see if anything changes and the answer is no. I've since found out (after I wrote this question originally) that my dataSource association is disappearing at some stage.

  • 下面包含的代码在数据源类的awakeFromNib上运行一次,并且运行良好.
  • 我的问题在任何其他时间调用.我没有调试错误,但我的outlineView保持不变.
  • 我将其范围缩小为可以在[outlineView dataSource]的NSLog上运行.从awakeFromNib调用该方法时,它会正确返回dataSource作为我的dataSourceClass.每隔两次它将数据源返回为 nil .
  • dataSourceSource已绑定到 InterfaceBuilder 中的outlineView.
  • 我对代码数组中的对象更新所做的所有其他NSLog检查会以正确的更新按预期返回.实际上,我检查了最后的 projectsArray clientsArray ,它们包含在尝试在outlineView中创建节点之前引入的所有新对象.
  • 我正在使用标准的xcode生成的核心数据应用委托代码.
  • 我没有使用NSTreeController,而是使用了自己的NSOutlineViewDataSource.基于两个核心数据实体的父/子关系,如何(或未记录)如何填充outlineView.
  • 我还将在下面包含我的NSOutlineViewDataSource代码.
  • the code included below is run once on awakeFromNib of the datasource class and works perfectly.
  • It is on calling it at any other time that my problem arrises. I get no errors debugging but my outlineView remains unchanged.
  • I narrowed this down to running on NSLog of [outlineView dataSource]. When the method is called from awakeFromNib it returns the dataSource as being my dataSourceClass correctly. Every other time it returns the dataSource as nil.
  • the dataSourceClass was bound to the outlineView in InterfaceBuilder.
  • All other NSLog checks I've made to object updates in arrays of my code comes back as expected with correct updates. In fact, I checked the final projectsArray and clientsArray and they contain all new objects introduced before attempting to create nodes in the outlineView.
  • I'm using the standard xcode generated core data app delegate code.
  • I'm not using NSTreeController and using my own NSOutlineViewDataSource. It was not possible (or not documented) on how to populate an outlineView based on the parent/child relationships of two core-data entities.
  • I'll also include my NSOutlineViewDataSource code below.

更新1: 嗯...在我打电话给[outlineView reloadData]之前,我为[outlineView dataSource]尝试了NSLog,它返回为 nil .我最初是通过 interfaceBuilder 中的绑定将 dataSource 与OutlineView关联的.我现在假设这是我的问题.为什么要释放我的数据源?以及如果我无法阻止它被释放怎么办?

Update 1: Hmmm... just before I call [outlineView reloadData] I tried an NSLog for [outlineView dataSource] and it returned as nil. I associated the dataSource to the outlineView originally by bindings in interfaceBuilder. I'm now assuming this is my problem. Why is my datasource being released? and how do I get it back if I can't prevent it being released?

refreshOutLineView:

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

outlineViewDataSource:

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

推荐答案

在我看来,您好像在控制器中的数据而非数据模型中强加了树形结构.您不必将两个实体分成两个数组,然后将它们拔拔就可以创建树.绑定背后的想法是,控制器仅将数据模型链接到控件,而控件则在数据模型内显示对象图.

It looks to me like you are imposing a tree structure on the data in the controller instead of in the data model. You shouldn't have to fetch two entities into two arrays and then shoehorn them together to create your tree. The idea behind bindings is that controllers simply link the data model to the control and the control displays the object graph within the data model.

因此,我认为您需要备份并再次查看您的数据模型.我推断您需要这样的数据模型:

So, I think you need to back up and look at your data model again. I infer you need a data model something like this:

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

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

您想要一个轮廓,将客户端及其相关的Project对象显示为子级.

You want an outline that shows Clients with their related Project objects as children.

如果使用NSTreeController,则将树控制器绑定到具有projects

If you use NSTreeController you would bind the tree controller to the entity Client with a child path of projects

如果使用大纲数据源,则只需获取按需要排序的Client对象,然后根据需要返回它们及其项目.

If you use an Outline Data source, you would just fetch the Client objects sorted as you wish and then return them and their projects as needed.

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

The important thing here is that the outline or tree structure should be innate in the data model itself. If it is not, then you probably don't want the user looking at and thinking about the data in an outline form.

还请记住,数据模型是Model-View-Controller设计的整个层,而不仅仅是位的哑巴.它可以并且应该包含表示应用程序中活动数据所需的所有逻辑.可以说,数据模型是应用程序的核心,并根据需要添加了UI,网络或持久性.不要害怕在数据模型中放入与数据相关的逻辑.

Remember as well that the data model is an entire layer of the Model-View-Controller design and is not just a dumb store of bits. It can and should contain all the logic necessary to represent the active data in the app. Arguably, the data model is the core of the app with the UI, networking or persistence tacked on as needed. Don't be afraid to put logic related to the data in the data model.

这篇关于为什么我的NSOutlineView数据源为零?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆