Existe algo parecido com uma lista genérica em Cocoa / Objective-C?

O que eu realmente gosto em c # são listas genéricas. Uma lista que pode conter apenas um tipo de object. Existe algo como uma lista genérica em Cocoa / Objective-C? Até agora eu só conheço o NSArray que irá pegar um ponteiro para qualquer object.

Querer isso em um aplicativo Cocoa é muitas vezes um sinal de um design fraco.

NSArray é imutável, portanto, ele não “pegará um ponteiro para nenhum object” e, presumivelmente, já conterá os objects corretos quando entregue a você. O que eu suponho que você está mais preocupado é um NSMutableArray onde você acha que outras partes do seu código podem adicionar o tipo errado de object. Mas dê uma olhada no próprio Cocoa; é incrivelmente raro expor um array mutável como parte do design de uma class.

Em vez disso, você geralmente expõe um NSArray e alguns methods para modificar esse array. Algo ao longo das linhas de:

 @class Foo : NSObject - (NSArray *)bars; - (void)addBar:(Bar *)bar; - (void)removeBar:(Bar *)bar; @end 

Isso geralmente impede que objects errados sejam inseridos simplesmente por ter um aviso de compilador, e então é claro que você pode adicionar asserções dentro de -addBar: e -removeBar: se você desejar também.

O Objective-C não suporta programação genérica. Você sempre pode usar o Objective-C ++ e uma lista STL.

NSArrays genéricos podem ser realizados subclassificando o NSArray e redefinindo todos os methods fornecidos com methods mais restritivos. Por exemplo,

 - (id)objectAtIndex:(NSUInteger)index 

teria que ser redefinido em

 @interface NSStringArray : NSArray 

Como

 - (NSString *)objectAtIndex:(NSUInteger)index 

para um NSArray conter apenas NSStrings.

A subclass criada pode ser usada como uma substituição imediata e traz muitos resources úteis: avisos de compilador, access à propriedade, melhor criação de código e conclusão no Xcode. Todos esses são resources de tempo de compilation, não há necessidade de redefinir a implementação real – os methods do NSArray ainda podem ser usados.

É possível automatizar isso e reduzi-lo a apenas duas instruções, o que o aproxima de linguagens que suportam genéricos. Eu criei uma automação com WMGenericCollection , onde modelos são fornecidos como macros de pré-processador C.

Depois de importar o arquivo de header que contém a macro, você pode criar um NSArray genérico com duas instruções: uma para a interface e outra para a implementação. Você só precisa fornecer o tipo de dados que deseja armazenar e os nomes de suas subclasss. WMGenericCollection fornece tais modelos para NSArray , NSDictionary e NSSet , bem como seus equivalentes mutáveis.

Não, o Objective-C atualmente não suporta digitação paramétrica para elementos de coleção.

No entanto, este tópico é mais complexo do que a questão ou as respostas existentes admitem.

Parametric-Typing para collections em Objective-C não seria o mesmo que Generics em C # / Java. Por exemplo, é improvável que você veja o Objective-C adicionar a capacidade de assegurar que cada object adicionado a uma coleção seja um tipo ou subtipo NSArray. Em vez disso, o Objective-C poderia (e o IMO deveria) ter a capacidade de assegurar que todos os objects em uma coleção CONFORMEM um protocolo / interface. (isto é, que implementa um conjunto de methods requeridos)

Por quê?

Objective-C é uma linguagem baseada na compatibilidade de protocolos (interface), não em relacionamentos de subtipagem. Ou seja, os objects são compatíveis se tiverem todos os methods corretos, não olharmos ou nos importarmos com seus tipos reais. De fato, olhar para tipos reais é uma prática muito ruim em Obj-C e altamente desencorajada. Essa noção é às vezes chamada de “Duck Typing”, porque se é como um pato, é um pato. Nós não nos importamos se literalmente herdou de algum pato específico ou não. Isso impede que você seja sobrecarregado pela hierarquia de implementação de outra pessoa. – O resultado é que, desde que um object que saia da lista tenha um método draw :: method, nós não nos importamos se é uma subclass de algum object específico do JimmyDrawableBase.

Isso não apenas torna o código mais reutilizável, mas também incentiva um tipo de decomposição de problema um pouco diferente (mais funcional?), Porque você não pode confiar em objects derivados de uma determinada class base e ter um monte de sua class base implementação forçada para eles.

Eu pessoalmente acho que seria bom para o compilador Obj-C ter uma verificação paramétrica de PROTOCOL * CONFORMANCE *. Isto é, para fazer um NSMutableArray que requer que todos os objects colocados nele estejam em conformidade com um determinado protocolo (ou seja, tenha um determinado conjunto de methods requeridos).

Às vezes, até mesmo essa verificação de conformidade de protocolo mais flexível é evitada por pessoas de programação dinâmica e com motivos sólidos. Os programadores geralmente têm uma maneira de especificar requisitos de conformidade.

Por exemplo, você pode exigir que uma lista contenha objects em conformidade com o protocolo / interface NSArray, mas você pode REALMENTE chamar apenas dois desses methods. Isso é excesso de conformidade. Alguém que deseja colocar um item compatível em sua matriz é forçado a implementar uma tonelada de methods que você não está realmente chamando – pelo menos ainda não (veja a seguir).

O Google Go tenta resolver esse problema inferindo a compatibilidade estrutural. Isto é, se você chamar draw () em itens que saem de uma lista, então o compilador assegura que tudo que entra em uma lista contenha um método draw (). Se não contiver um método draw (), é um erro do compilador para colocá-lo na lista. Isso impede que o código simplesmente cause o mesmo erro durante a execução. O problema com isso é que ele só funciona para compilation de todo o programa. Se o Google-Go pudesse compilar DLLs modulares (o que não é possível), ele teria o problema de não haver nenhuma maneira de dizer que os objects da lista precisam suportar uma interface específica de três methods, embora Eu não estou ligando para eles hoje, porque eu posso ligar para eles no futuro .

Entre essas duas soluções, a troca e a verdade.

Pessoalmente, eu gostaria de ver o Objective-C adicionar a conformidade com o protocolo paramétrico, então eu poderia pedir ao compilador para assegurar que o conteúdo de uma coleção particular esteja sempre em conformidade com um determinado conjunto de protocolos.

Eu também gostaria que o compilador me ajudasse a evitar o excesso de conformidade. Se eu não estou chamando methods nesses protocolos em objects, ele deve gerar erros / avisos dizendo isso. Se eu quiser mantê-los no protocolo mesmo que eu não os esteja usando, eu teria que fazer explicitamente uma declaração para cada método no protocolo que “poderia ser usado no futuro, então todos os elementos precisam fornecê-los agora “. Isso pelo menos faz com que o processo de excesso de conformidade exija mais trabalho, em vez de Java / C #, onde requer menos trabalho.