Comment convertir NSMutableArray en NSArray?

381

Comment convertir NSMutableArray en NSArray dans ?

marcy
la source
12
justeNSArray *array = [mutableArray copy];
béryllium
1
NSArray *array = mutableArray;
vladof81
4
béryllium: tout à fait raison. vladof81: Bien sûr que non.
gnasher729

Réponses:

511
NSArray *array = [mutableArray copy];

Copyfait des copies immuables. C'est très utile car Apple peut effectuer diverses optimisations. Par exemple, l'envoi copyà un tableau immuable ne conserve que l'objet et retourne self.

Si vous n'utilisez pas le ramasse-miettes ou ARC, n'oubliez pas que -copyconserve l'objet.

Georg Schölly
la source
2
cette réponse est excellente, mais comment savoir à partir des documents qui copycréent un NSArray normal et non un NSMutableArray?
Dan Rosenstark
22
@Yar: Vous regardez la documentation de NSCopying Il y est indiqué : copyWithZone La copie retournée est immuable si la considération «immuable vs mutable» s'applique à l'objet récepteur; sinon, la nature exacte de la copie est déterminée par la classe.
Georg Schölly
1
Très soigné - je préfère cela à la solution de m5h. À la fois concis et plus efficace.
David Snabel-Caunt
1
Je suis d'accord David, a mis à jour ma réponse pour pointer vers cette réponse.
hallski
2
@Brad: Cela signifie simplement des classes qui ont à la fois des implémentations mutables et immuables. Par exemple NSArray& NSMutableArray, NSString& NSMutableString. Mais pas par exemple NSViewControllerqui contient toujours un état mutable.
Georg Schölly
361

An NSMutableArrayest une sous-classe de NSArraydonc vous n'aurez pas toujours besoin de convertir, mais si vous voulez vous assurer que le tableau ne peut pas être modifié, vous pouvez créer l'une NSArrayou l'autre de ces façons selon que vous souhaitez qu'il soit libéré automatiquement ou non:

/* Not autoreleased */
NSArray *array = [[NSArray alloc] initWithArray:mutableArray];

/* Autoreleased array */
NSArray *array = [NSArray arrayWithArray:mutableArray];

EDIT: La solution fournie par Georg Schölly est une meilleure façon de le faire et beaucoup plus propre, surtout maintenant que nous avons ARC et que nous n'avons même plus besoin d'appeler la libération automatique.

hallski
la source
7
Puis-je simplement faire (NSArray *) myMutableArray?
Vojto
2
Oui, car NSMutableArray est une sous-classe de NSArray qui est valide.
hallski
4
Cependant, la conversion vers (NSArray *) permet toujours une conversion vers (NSMutable *). N'est-ce pas le cas?
sharvey
1
@sharvey: Oui, c'est exact. Vous obtiendrez un avertissement si vous ne lancez pas mais assignez directement une superclasse à une sous-classe. Habituellement, vous souhaitez renvoyer une copie immuable, car c'est la seule façon d'être sûr que votre tableau ne sera vraiment pas modifié.
Georg Schölly
1
Anciennement connu sous le nom de "Upcasting" (NSArray *) myMutableArray et l'inverse est appelé "Downcasting"
Francisco Gutiérrez
113

J'aime les deux solutions principales:

NSArray *array = [NSArray arrayWithArray:mutableArray];

Ou

NSArray *array = [mutableArray copy];

La principale différence que je vois en eux est la façon dont ils se comportent lorsque mutableArray est nul :

NSMutableArray *mutableArray = nil;
NSArray *array = [NSArray arrayWithArray:mutableArray];
// array == @[] (empty array)

NSMutableArray *mutableArray = nil;
NSArray *array = [mutableArray copy];
// array == nil
Richard Venable
la source
C'est tellement faux. Je viens de vérifier. [copie mutableArray] renvoie également un tableau vide.
durazno
@durazno Ce n'est pas faux. Vérifiez votre test. Si [copie mutableArray] renvoie un tableau vide, alors mutableArray doit être un tableau vide. Ma réponse ne s'applique que lorsque mutableArray est nul.
Richard Venable
Bien que cela soit vrai, j'ai l'impression que vous manquez une vérité plus fondamentale dans votre exemple. Puisque vous avez affecté mutableArray à nil, [mutableArray copy]peut être simplifié en [nil copy]. Dans objective-c, tout message envoyé à nil sera toujours nul. Il est important de se rappeler la distinction entre "rien" et "un tableau sans rien".
mkirk
@mkirk Ne nous distrayons pas de la question posée: "Comment convertir NSMutableArray en NSArray?" Il existe 2 solutions principales, et la principale différence entre elles est la manière dont elles se comportent lorsque le tableau mutable est nul.
Richard Venable
18

vous essayez ce code ---

NSMutableArray *myMutableArray = [myArray mutableCopy];

et

NSArray *myArray = [myMutableArray copy];
Jerry Thomsan
la source
Qu'est-ce que cela fait que les autres ne font pas?
Ben Leggiero
5

Objectif c

Vous trouverez ci-dessous un moyen de convertir NSMutableArray en NSArray:

//oldArray is having NSMutableArray data-type.
//Using Init with Array method.
NSArray *newArray1 = [[NSArray alloc]initWithArray:oldArray];

//Make copy of array
NSArray *newArray2 = [oldArray copy];

//Make mutablecopy of array
NSArray *newArray3 = [oldArray mutableCopy];

//Directly stored NSMutableArray to NSArray.
NSArray *newArray4 = oldArray;

Rapide

Dans Swift 3.0, il existe un nouveau type de données Array . Déclarez Array en utilisant un letmot-clé, il deviendrait NSArray. Et si vous déclarez en utilisant un varmot-clé, il deviendrait NSMutableArray .

Exemple de code:

let newArray = oldArray as Array
Sakir Sherasiya
la source
La partie Swift n'est pas tout à fait raison. Voir ici et ici pour la différence entre les Arrays et NSArray/ NSMutableArrays mutables / immuables . Ils ne sont pas les mêmes.
Bruno Ely
3

Dans l'objectif-c:

NSArray *myArray = [myMutableArray copy];

En bref:

 var arr = myMutableArray as NSArray
Vikram Biwal
la source
2
NSArray *array = mutableArray;

Cet [mutableArray copy]antipattern est partout dans l'exemple de code. Arrêtez de le faire pour les tableaux mutables jetables qui sont transitoires et qui sont désalloués à la fin de la portée actuelle.

Il n'y a aucun moyen que le runtime optimise la copie inutile d'un tableau mutable qui est sur le point de sortir de la portée, décréfé à 0 et désalloué pour de bon.

Anton Tropashko
la source
Assigner un NSMutableArrayà une NSArrayvariable ne le convertira pas (c'est la question du PO). L'exposition d'une telle valeur (par exemple en tant que valeur de retour ou en tant que propriété) pourrait entraîner des problèmes de débogage très difficiles si cette valeur était modifiée de manière inattendue. Cela s'applique aux mutations internes et externes, car la valeur mutable est partagée.
David Rönnqvist
Pour muter ce tableau, vous devez [NSMutableArray arrayWithArray: ... ou quelque chose comme ça.
Anton Tropashko
Pas nécessairement. Il suffit de l'assigner à une NSMutableArrayvariable. Étant donné que l'objet n'a jamais cessé d'être un tableau mutable, l'appel de méthodes de mutation réussira et mutera les données partagées. Si, d'autre part, le tableau mutable d'origine était copié - en le changeant en un tableau immuable - puis assigné à une NSMutableArrayvariable et que des méthodes de mutation y étaient appelées, ces appels échoueraient avec des doesNotRespondToSelectorerreurs car l'objet qui a reçu l'appel de méthode de mutation est dans fait immuable et ne répond pas à ces méthodes.
David Rönnqvist
ok, cela pourrait avoir un certain mérite pour les développeurs qui ne tiennent pas compte de l'avertissement du compilateur sur les affectations de conversion de tyope
Anton Tropashko
1

Si vous construisez un tableau via la mutabilité et que vous souhaitez ensuite retourner une version immuable, vous pouvez simplement retourner le tableau mutable en tant que "NSArray" via l'héritage.

- (NSArray *)arrayOfStrings {
    NSMutableArray *mutableArray = [NSMutableArray array];
    mutableArray[0] = @"foo";
    mutableArray[1] = @"bar";

    return mutableArray;
}

Si vous "faites confiance" à l'appelant pour traiter l'objet de retour (techniquement encore modifiable) comme un NSArray immuable, c'est une option moins coûteuse que [mutableArray copy].

Apple est d'accord:

Pour déterminer s'il peut modifier un objet reçu, le destinataire d'un message doit s'appuyer sur le type formel de la valeur de retour. S'il reçoit, par exemple, un objet tableau typé immuable, il ne doit pas tenter de le muter . Ce n'est pas une pratique de programmation acceptable de déterminer si un objet est modifiable en fonction de son appartenance à la classe.

La pratique ci-dessus est discutée plus en détail ici:

Meilleure pratique: renvoyer mutableArray.copy ou mutableArray si le type de retour est NSArray

pkamb
la source
0

je cherchais la réponse dans swift 3 et cette question a été montrée comme premier résultat dans la recherche et je suis inspiré de la réponse alors voici le code swift 3

let array: [String] = nsMutableArrayObject.copy() as! [String]
Amr Angry
la source