Pergunta

Eu tenho um NSDocument que tem a seguinte estrutura:

@interface MyDocument : NSDocument
{
    NSMutableArray *myArray;

    IBOutlet NSArrayController *myArrayController;
    IBOutlet MyView *myView;
}
@end

Eu instanciar o NSArrayController eo MyView em MyDocument.xib, e fizeram as conexões para o dono do arquivo (MyDocument), então eu tenho certeza que, do ponto de vista da Interface Builder, tenho feito tudo corretamente.

A interface para MyView é simples:

@interface MyView : NSView {
    NSMutableArray *myViewArray;
}
@end

Agora, em MyDocument windowControllerDidLoadNib, eu tenho o código a seguir:

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];
    [myArrayController setContent:myArray];
// (This is another way to do it)    [myArrayController bind:@"contentArray" toObject:self withKeyPath:@"myArray" options:nil];

    [myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"arrangedObjects" options:nil];
}

No depurador, tenho verificado que myViewArray é um NSControllerArrayProxy, então parece que a minha ligação programática está correto. No entanto, quando eu tento adicionar objetos em métodos de MyView ao myViewArray MyView, eles não aparecem para atualizar myArray do MyDocument. Eu tentei ambas as seguintes abordagens:

[myViewArray addObject:value];
[self addMyViewArraysObject:value];

(A segunda abordagem faz com que um erro do compilador, como esperado, mas eu pensei que o tempo de execução Objective-C seria "implementar" este método por minha compreensão limitada de KVO.)

Existe errado algo com a forma como eu estou tentando atualização myViewArray? Existe errado algo com ligação minha programático? (Eu estou tentando fazer isso programaticamente, porque MyView é uma exibição personalizada e eu não quero criar uma paleta IB para ele.)

Foi útil?

Solução

O problema é que você está transformando sua matriz diretamente. Implementar indexada métodos de acesso e chamar aqueles.

KVO substitui seus métodos de acesso (contanto que você se conforma com determinados formatos ) e mensagens as notificações necessárias. Você não consegue isso quando você falar diretamente com sua matriz; qualquer coisa ligada à propriedade não vai saber que você mudou a propriedade, a menos que você diga a ele explicitamente. Quando você usa os seus métodos de acesso, KVO diz aos outros objetos para você.

A única vez para não usar seus métodos de acesso (sintetizado ou não) está em init e dealloc, desde que você estaria falando com um objeto de metade inited ou -deallocked.

Uma vez que você estiver usando seus próprios métodos de acesso a mutação da matriz, e obtendo, assim, as notificações KVO livres, as coisas devem apenas trabalho:

  • A vista, quando mutação sua propriedade, irá notificar automaticamente o controlador de matriz, que transforma sua propriedade content, que notifica o controlador.
  • O seu controlador, quando mutação sua propriedade, irá notificar automaticamente o controlador de matriz, que transforma sua propriedade arrangedObjects, que notifica a vista.

Outras dicas

Eu posso ver duas possibilidades aqui:

Primeiro, você instanciar o objeto NSMutableArray (e liberá-lo) em sua classe MyDocument? Deve ser algo como isto:

- (id)init
{
    if ((self = [super init]) == nil) { return nil; }
    myArray = [[NSMutableArray alloc] initWithCapacity:0];
    return self;
}

- (void)dealloc
{
    [myArray release];
    [super dealloc];
}

Em segundo lugar, se você declarar myViewArray como uma propriedade em MyView? Deve ser algo como isto:

// MyView.h:
@interface MyView : NSView
{
    NSMutableArray * myViewArray;
}
@property (assign) NSMutableArray * myViewArray;
@end
// MyView.m:
@implementation MyView

@synthesize myViewArray;

@end

Além disso, parece-me que você tem feito tudo da ligação corretamente.

atualização: Que tal usar o NSArrayController para adicionar itens para a matriz:

// MyView.h:
@interface MyView : NSView
{
    NSMutableArray * myViewArray;
    IBOutlet NSArrayController * arrayController;
}
@property (assign) NSMutableArray * myViewArray;
- (void)someMethod;
@end
// MyView.m:
@implementation MyView

@synthesize myViewArray;

- (void)someMethod
{
    id someObject = [[SomeClass alloc] init];
    [arrayController addObject:[someObject autorelease]];
}

@end

O problema parece ser que eu tinha sido vinculativo myViewArray de MyView à propriedade arrangedObjects do NSArrayController vez de sua propriedade content.

Quando ligação a arrangedObjects, descobri que o objeto real apontado por myViewArray era uma instância de NSControllerArrayProxy . Eu não encontrei uma resposta definitiva quanto ao que este objeto realmente faz quando eu procurou online para obter mais informações sobre ele. No entanto, os exemplos de código I encontrados sugerem que NSControllerArrayProxy é destinado para expor conveniências para acessar o propriedades de objetos na matriz , em vez dos objetos (na matriz)-se. É por isso que eu acredito que eu estava enganado na ligação a arrangedObjects.

A solução foi, em vez ligam myViewArray de MyView para content propriedade do NSArrayController:

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
    [super windowControllerDidLoadNib:aController];

    [myArrayController setContent:myArray];
    [myView bind:@"myViewArray" toObject:myArrayController withKeyPath:@"content" options:nil];
}

Embora este parece funcionar, eu não estou 100% de certeza que é correto vincular a content , neste caso. Se alguém pode lançar alguma luz sobre programaticamente ligação às várias propriedades de um NSArrayController, eu gostaria de receber comentários a esta resposta. Obrigado.

Em primeiro lugar, não há nada errado com a ligação a arrangedObjects: um NSTableColumn, por exemplo, deve ter seu conteúdo vinculado a apenas arrangedObjects, e seus contentValues ??para arrangedObjects.someProperty.

O erro comum é arrangedObjects consideram como o conteúdo de um arrayController mas que, como você viu, vai levar a dor: arrangedObjects é uma representação da forma como o arrayController tem atualmente dispostos os objetos em seu conteúdo, não o conteúdo em si.

Dito isto, a maneira de vincular uma matriz para um arrayController é:

[self.myArrayController bind:NSContentArrayBinding 
 toObject:self
 withKeyPath:@"myView.myViewArray" 
 options:nil]; 

Você tem certeza, aliás, a sua visão precisa segurar o myViewArray? Isso geralmente cai sob a responsabilidade de um objeto controlador ou modelo.

Agora você pode adicionar objetos ao chamar addObject na arrayController , uma vez que é da responsabilidade do controlador.

[self.myArrayController addObject: anObject]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top