Pergunta

Estou inicializando uma interface simples, com um NSTableView ligado a um controlador de matriz (que gerencia uma variedade de dicionários). Quero carregar o conteúdo da matriz em segundo plano (é um processo muito demorado), atualizando a visualização da tabela a cada 100 ou 1000 elementos. A idéia é que a interface esteja disponível e receptiva. Não consigo descobrir como acionar também uma atualização / atualização depois. A tabela permanece vazia. Alguém pode oferecer ponteiros?

Minha abordagem atual é:

// In init for my app controller. This seems to work well, but I've tried other methods here.
[self performSelectorInBackground:@selector(loadTable) withObject:nil];


- (void)loadTable {
  tracks = [[NSMutableArray alloc] initWithCapacity:[masters count]];

  // ... create each object one-by-one. Add it to tracks.
  for (... in ...) {
    [tracks addObject:newObject];
  }

  // Now I don't know what to do next. The table remains empty. 
  // Things I've tried (though possibly not in all combinations with the
  // method above):
  // 1. With a suitably-defined reloadData method, which just reloads
  //   the table view and sets needs display.
  [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];

  // 2. Reload directly.
  [tv reloadData];
  [tv setNeedsDisplay];
}

Se eu apenas carregar os dados diretamente e não tentar fazer isso em segundo plano, tudo funciona bem, mas leva quase 30 anos.

Foi útil?

Solução

Você tem as colunas da tabela (presumo que você quis dizer) vinculado a um controlador de matriz, então é daí que a exibição da tabela obtém seus dados. A visualização da tabela pode muito bem estar pedindo matrizes atualizadas, mas está pedindo ao controlador da matriz, o que não sabe que nada mudou.

O controlador da matriz não simplesmente se vira e solicita novos dados; Isso implicaria que existe apenas para dificultar a ligação da exibição da tabela à sua matriz, e esse não é o caso. É um controlador; Seu trabalho é possuir (uma cópia de) a matriz e manter sua ordem e a seleção do usuário de algum subconjunto de seus objetos.

Portanto, você precisa do controlador de matriz para descobrir quando adiciona itens à sua matriz. A melhor maneira de fazer isso acontecer é vincular o controlador de matriz contentArray para uma propriedade do seu controlador e atualize essa propriedade de maneira compatível com KVO.

Que significa:

  1. Crie a matriz mutável em seu init método. (E, é claro, solte -o em dealloc.)
  2. Implemento os métodos de acessórios de matriz, mais addTracksObject: e removeTracksObject: (que são tecnicamente definidos métodos de acessórios, portanto, o KVO os ignorará para uma propriedade da matriz) para sua conveniência.
  3. Para adicionar uma faixa, envie -se um addTracksObject: mensagem. Você deve responder a isso enviando um insertObject:inTracksAtIndex: mensagem (com [self countOfTracks] para o índice, a menos que você queira fazer um insort), e você deve responder a insertObject:inTracksAtIndex: enviando o seu tracks Array An insertObject:atIndex: mensagem.

Como mencionei, o KVO irá ignorar addFooObject: e removeFooObject: quando foo é uma propriedade NSarray, considerando os apenas acessores de propriedades NSSET, então você precisa implementá-los em cima insertObject:inFooAtIndex: e removeObjectFromFooAtIndex: Porque aqueles são Acessores de matriz, o que significa que o KVO reagirá a eles.

Etapa 3, como acabei de descrevê-lo, será muito lento, porque fará arrangedObjects Pelo menos uma vez cada um para cada linha que você adiciona.

Portanto, você deve manter seu comportamento de adição de lote com esta etapa alternativa 3:

  • Implemento insertTracks:atIndexes:, e passar uma matriz de um lote de (por exemplo, 100 ou 1000) faixas e um conjunto de índices formado por [NSIndexSet indexSetWithRange:(NSRange){ [self countOfTracks], countOfBatch }]. Você também precisará implementar removeTracksAtIndexes:, apenas porque o KVO ignorará cada método de inserção se você também não tiver sua contraparte.

Você provavelmente deve ter o controlador de matriz definido para tentar preservar a seleção, para não frustrar muito o usuário enquanto ainda está trazendo linhas.

Além disso, convém criar os objetos em um encadeamento de segundo plano, enviando periodicamente outro lote para adicionar usando um desempenho principal. Normalmente, sou um defensor de fazer as coisas no loop de execução do encadeamento principal sempre que possível, mas esse tipo de coisa pode facilmente deixar sua interface lenta enquanto sua carga periódica aumenta outro lote.

Outras dicas

Você precisa ligar setNeedsDisplay:YES na sua tabela visualização no segmento principal. Não chame de um tópico de fundo. Todas as chamadas de interface do usuário do cacau devem ser feitas no fio principal ou coisas estranhas acontecem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top