Estou procurando o idioma padrão para iterar sobre um NSArray. Meu código precisa ser adequado para o OS X 10.4+.
fonte
Estou procurando o idioma padrão para iterar sobre um NSArray. Meu código precisa ser adequado para o OS X 10.4+.
O código geralmente preferido para 10.5 + / iOS.
for (id object in array) {
// do something with object
}
Essa construção é usada para enumerar objetos em uma coleção em conformidade com o NSFastEnumeration
protocolo. Essa abordagem tem uma vantagem de velocidade porque armazena ponteiros para vários objetos (obtidos através de uma única chamada de método) em um buffer e itera através deles, avançando pelo buffer usando a aritmética do ponteiro. Isso é muito mais rápido do que ligar -objectAtIndex:
todas as vezes no loop.
Também é importante notar que, embora tecnicamente você possa usar um loop for-in para percorrer um NSEnumerator
, descobri que isso anula praticamente toda a vantagem de velocidade da enumeração rápida. O motivo é que a NSEnumerator
implementação padrão de -countByEnumeratingWithState:objects:count:
coloca apenas um objeto no buffer em cada chamada.
Eu relatei isso em radar://6296108
(A enumeração rápida de NSEnumerators é lenta), mas foi retornada como Não deve ser corrigido. O motivo é que a enumeração rápida busca previamente um grupo de objetos e se você deseja enumerar apenas um determinado ponto do enumerador (por exemplo, até que um objeto específico seja encontrado ou a condição seja atendida) e use o mesmo enumerador após a quebra do loop, muitas vezes seria o caso de vários objetos serem ignorados.
Se você estiver codificando para o OS X 10.6 / iOS 4.0 e superior, também terá a opção de usar APIs baseadas em bloco para enumerar matrizes e outras coleções:
[array enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// do something with object
}];
Você também pode usar -enumerateObjectsWithOptions:usingBlock:
e passar NSEnumerationConcurrent
e / ou NSEnumerationReverse
como argumento de opções.
O idioma padrão para pré-10.5 é usar um NSEnumerator
loop while, como:
NSEnumerator *e = [array objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
}
Eu recomendo mantê-lo simples. Amarrar-se a um tipo de matriz é inflexível e o suposto aumento de velocidade do uso -objectAtIndex:
é insignificante para a melhoria com a enumeração rápida em 10.5 ou superior. (A enumeração rápida realmente usa aritmética de ponteiro na estrutura de dados subjacente e remove a maior parte da sobrecarga de chamada do método.) Otimização prematura nunca é uma boa idéia - resulta em código mais confuso para resolver um problema que não é seu gargalo.
Ao usar -objectEnumerator
, você muda muito facilmente para outra coleção enumerável (como NSSet
, chaves em um NSDictionary
etc.) ou muda -reverseObjectEnumerator
para enumerar uma matriz de trás para frente, tudo sem outras alterações de código. Se o código de iteração estiver em um método, você pode até mesmo passar algum NSEnumerator
e o código nem precisa se preocupar com o que está iterando. Além disso, um NSEnumerator
(pelo menos aqueles fornecidos pelo código da Apple) retém a coleção que está enumerando, desde que haja mais objetos, para que você não precise se preocupar por quanto tempo um objeto liberado automaticamente existirá.
Talvez a maior coisa que uma NSEnumerator
(ou enumeração rápida) proteja você seja ter uma coleção mutável (matriz ou outra) alterada abaixo de você sem o seu conhecimento enquanto você a enumera. Se você acessar os objetos por índice, poderá encontrar estranhas exceções ou erros pontuais (geralmente muito tempo após o problema) que podem ser horríveis para depuração. A enumeração usando um dos idiomas padrão possui um comportamento "fail-fast"; portanto, o problema (causado por código incorreto) se manifestará imediatamente quando você tentar acessar o próximo objeto após a mutação. À medida que os programas ficam mais complexos e com vários threads, ou até mesmo dependem de algo que o código de terceiros pode modificar, o código de enumeração frágil se torna cada vez mais problemático. Encapsulamento e abstração FTW! :-)
for (id object in array)
, existe uma maneira de determinar também o índice atual de objetos na matriz ou um contador separado precisa ser incluído?for
loop como este:for(;;) { id object = [ e nextObject ] ; if ( !e ) { break ; } ... your loop operation ... }
Para OS X 10.4.xe anterior:
Para OS X 10.5.x (ou iPhone) e além:
fonte
for (NSUInteger i = 0, count = [myArray count]; i < count; i++)
é provavelmente o mais eficiente e conciso que você terá para essa abordagem.Os resultados do teste e do código-fonte estão abaixo (você pode definir o número de iterações no aplicativo). O tempo é em milissegundos e cada entrada é um resultado médio da execução do teste 5 a 10 vezes. Descobri que geralmente é preciso ter de 2 a 3 dígitos significativos e depois variaria a cada execução. Isso dá uma margem de erro inferior a 1%. O teste estava sendo executado em um iPhone 3G, pois essa é a plataforma de destino em que eu estava interessado.
As classes fornecidas pelo Cocoa para lidar com conjuntos de dados (NSDictionary, NSArray, NSSet etc.) fornecem uma interface muito agradável para gerenciar informações, sem ter que se preocupar com a burocracia de gerenciamento de memória, realocação etc. É claro que isso tem um custo . Eu acho que é bastante óbvio dizer que o uso de um NSArray de NSNumbers será mais lento que um C Array de flutuadores para iterações simples, então decidi fazer alguns testes e os resultados foram bastante chocantes! Eu não esperava que fosse tão ruim assim. Nota: esses testes são realizados em um iPhone 3G, pois essa é a plataforma de destino em que eu estava interessado.
Neste teste, faço uma comparação de desempenho de acesso aleatório muito simples entre um float C * e o NSArray of NSNumbers
Crio um loop simples para resumir o conteúdo de cada array e cronometrá-los usando mach_absolute_time (). O NSMutableArray leva em média 400 vezes mais! (não 400%, apenas 400 vezes mais! isso é 40.000% mais!).
Cabeçalho:
// Array_Speed_TestViewController.h
// Teste de velocidade da matriz
// Criado por Mehmet Akten em 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. Todos os direitos reservados.
Implementação:
// Array_Speed_TestViewController.m
// Teste de velocidade da matriz
// Criado por Mehmet Akten em 05/02/2009.
// Copyright MSA Visuals Ltd. 2009. Todos os direitos reservados.
De: memo.tv
////////////////////
Disponível desde a introdução dos blocos, isso permite iterar uma matriz com blocos. Sua sintaxe não é tão boa quanto a enumeração rápida, mas há um recurso muito interessante: enumeração simultânea. Se a ordem de enumeração não for importante e os trabalhos puderem ser feitos em paralelo sem travar, isso poderá fornecer uma aceleração considerável em um sistema com vários núcleos. Mais sobre isso na seção de enumeração simultânea.
/////////// NSFastEnumerator
A idéia por trás da enumeração rápida é usar o acesso rápido à matriz C para otimizar a iteração. Não é apenas mais rápido que o NSEnumerator tradicional, mas o Objective-C 2.0 também fornece uma sintaxe muito concisa.
///////////////////
NSEnumerator
Esta é uma forma de iteração externa: [myArray objectEnumerator] retorna um objeto. Este objeto tem um método nextObject que podemos chamar em um loop até que retorne nulo
///////////////////
objectAtIndex: enumeração
Usar um loop for que aumenta um número inteiro e consultar o objeto usando [myArray objectAtIndex: index] é a forma mais básica de enumeração.
////////////// De: darkdust.net
fonte
As três maneiras são:
fonte
Adicione
each
método no seuNSArray category
, você precisará muitoCódigo extraído do ObjectiveSugar
fonte
Aqui está como você declara uma matriz de seqüências de caracteres e itera sobre elas:
fonte
Para Swift
fonte
Faça isso :-
fonte