Почему мой источник данных NSOutlineView равен нулю? - PullRequest
0 голосов
/ 15 марта 2011

Это дополнительный вопрос из моего предыдущего, касающийся того, почему мой managedObjectContext возвращался к нулю.Я думал, что направление вопроса будет скрыто в старом.

Теперь я получаю mangedObjectContext , чтобы не возвращать ноль, и при выполнении [outlineView reloadData] с моим outlineView вообще ничего не происходит,Я попытался выборочно удалить части кода, предназначенные для обновления outlineView , чтобы увидеть, если что-то изменится, и ответ - нет.С тех пор я узнал (после того как я написал этот вопрос изначально), что моя связь с источником данных исчезает на каком-то этапе.

Примечания:

  • приведенный ниже код запускается один раз на awakeFromNibкласса источника данных и работает отлично.
  • Именно при вызове его в любое другое время возникает моя проблема.Я не получаю ошибок отладки, но мой outlineView остается неизменным.
  • Я сузил это до работы на NSLog [outlineView dataSource].Когда метод вызывается из awakeFromNib, он возвращает dataSource как мой dataSourceClass правильно.Каждый раз, когда он возвращает источник данных как nil .
  • , dataSourceClass был привязан к outlineView в InterfaceBuilder .
  • Все другие проверки NSLog I 'Внесенные в объект обновления в массивах моего кода возвращаются, как и ожидалось, с правильными обновлениями.Фактически, я проверил окончательные projectsArray и clientsArray , и они содержат все новые объекты, введенные перед попыткой создания узлов в outlineView.
  • Я использую стандартныйсгенерированный xcode код делегата приложения для основных данных.
  • Я не использую NSTreeController и использую свой собственный NSOutlineViewDataSource.Было невозможно (или не задокументировано), как заполнить outlineView на основе родительских / дочерних отношений двух сущностей базовых данных.
  • Я также включу свой NSOutlineViewDataSource код ниже.

Обновления:

Обновление 1: Хммм ... как раз перед тем, как позвонить [outlineView reloadData] Я попробовал NSLog для [outlineView dataSource], и он вернулся как ноль .Я изначально связал источник данных с outlineView с помощью привязок в interfaceBuilder .Теперь я предполагаю, что это моя проблема.Почему освобождается мой источник данных?и как мне вернуть его, если я не могу предотвратить его выпуск?

Код:

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

Ответы [ 2 ]

1 голос
/ 15 марта 2011

В большинстве случаев это означает, что вы случайно создали два экземпляра вашего класса.Один находится в вашем перо и подключен ко всему, в то время как другой либо создается в коде, либо создается в другом месте в перо без каких-либо соединений.Простой способ доказать, что это происходит, - зарегистрировать self как в awakeFromNib, так и какой-нибудь метод, который видит nil - вы увидите разные адреса для двух объектов.Вы также обнаружите, что outlineView само по себе равно нулю, поскольку розетка не подключена ни к чему.

0 голосов
/ 15 марта 2011

Мне кажется, что вы накладываете древовидную структуру на данные в контроллере, а не в модели данных. Вам не нужно собирать два объекта в два массива, а затем соединять их вместе, чтобы создать дерево. Идея связывания заключается в том, что контроллеры просто связывают модель данных с элементом управления, а элемент управления отображает граф объекта в модели данных.

Итак, я думаю, вам нужно выполнить резервное копирование и снова посмотреть на вашу модель данных. Я полагаю, вам нужна модель данных что-то вроде этого:

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

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

Требуется схема, которая показывает клиентов со связанными объектами проекта как дочерние.

Если вы используете NSTreeController, вы привязываете контроллер дерева к объекту Client с дочерним путем projects

Если вы используете источник Outline Data, вы просто выбираете объекты Client, отсортированные по вашему желанию, а затем возвращаете их и их проекты по мере необходимости.

Здесь важно то, что структура или древовидная структура должны быть врожденными в самой модели данных. Если это не так, то вы, вероятно, не хотите, чтобы пользователь смотрел и думал о данных в виде структуры.

Помните также, что модель данных - это целый слой конструкции Model-View-Controller, а не просто тупое хранилище битов. Он может и должен содержать всю логику, необходимую для представления активных данных в приложении. Можно утверждать, что модель данных является ядром приложения с пользовательским интерфейсом, сетью или постоянством, привязанными по мере необходимости. Не бойтесь помещать логику, связанную с данными, в модель данных.

...