Qual é a melhor maneira de usar as propriedades do Obj-C 2.0 com objects mutáveis, como NSMutableArray?

Eu tenho uma class Obj-C 2.0 que possui uma propriedade NSMutableArray. Se eu usar o seguinte código, o setter sintetizado me dará uma cópia imutável, não mutável:

@property (readwrite, copy) NSMutableArray *myArray; 

Existe algum motivo para a Apple não ter implementado a seguinte syntax?

 @property (readwrite, mutablecopy) NSMutableArray *myArray; 

Já que não temos a mutablecopy , qual é a melhor maneira de lidar com essa situação (aparentemente comum)? Devo apenas escrever meu próprio setter que faz um -mutableCopy?

Como dito antes, o jeito certo de fazer isso não é tornar a matriz mutável uma propriedade. Há uma ótima explicação do que você deve implementar para ser compatível com KVC aqui .

Eu encontrei o mesmo problema há algum tempo e encontrei um documento na Apple Developer Connection recomendando que você fornecesse sua própria implementação do setter. Exemplo de código do documento vinculado:

 @interface MyClass : NSObject { NSMutableArray *myArray; } @property (nonatomic, copy) NSMutableArray *myArray; @end @implementation MyClass @synthesize myArray; - (void)setMyArray:(NSMutableArray *)newArray { if (myArray != newArray) { [myArray release]; myArray = [newArray mutableCopy]; } } 

Não é comum passar por NSMutableArray em Cocoa. A prática padrão do Cocoa seria implementar os methods compatíveis com a codificação do valor-chave para uma propriedade indexada para muitos. Isso tem dois benefícios:

  1. A observação de valores-chave funciona como esperado (há vários casos em que observar um NSMutableArray leva a um comportamento que não é o que você quer)
  2. A implementação de sua estrutura de dados está oculta porque você expõe methods -[MyObject insertObjectInMyProperty:(id)newObject atIndex:(NSUInteger)i] (por exemplo -[MyObject insertObjectInMyProperty:(id)newObject atIndex:(NSUInteger)i] , não a estrutura de dados propriamente dito.

Tenha em mente que passar em torno de um array mutável não é uma prática comum em Cocoa. Você pode usar um array mutável privado como armazenamento interno, mas criar methods usando objects simples do NSArray para adicionar ou obter objects dele. Talvez seja por isso que não há declaração de propriedade de mutablecopy.

Você terá que escrever seu próprio setter.

O caminho certo para segurar um NSMutableArray é com uma propriedade de retenção:

 @property (nonatomic, retain) NSMutableArray *myArray; 

Você não precisa escrever seu próprio setter ou usar a cópia. A propriedade copy deve ser usada com um NSArray que realmente precisa ser copiado quando a propriedade é capturada em outro object. Por exemplo, se você atribuir um object NSMutableArray a uma propriedade do tipo NSArray com a propriedade copy, desejará fazer uma cópia do array mutável para “capturá-lo” como uma propriedade imutável desse ponto em diante.

E Marc tem a abordagem correta, normalmente não faria com que NSMutableArray fizesse parte da API pública de seus objects. Se você tiver uma propriedade pública, pode ser um NSArray com a propriedade copy.