2009-06-10 8 views
2

J'ai ce problème avec Cocoa, je fais appel une fonction et le passage d'un tableau à elle:Passant NSMutableArray en fonction

Certains où j'appelle la fonction:

[self processLabels:labels]; 

Et la fonction est la suivre:

- (void)processLabels:(NSMutableArray*)labs{ 
    labs = [[NSMutableArray alloc] init]; 
    [labs addObject:@"Random"]; 
.... 
} 

lors du débogage, je remarque qu'aucun nouvel objet sont ajoutées aux étiquettes lorsqu'ils sont ajoutés aux laboratoires. Est-ce parce que je réinitialise les laboratoires? comment puis-je réinitialiser les étiquettes à l'intérieur de la fonction alors?

J'ai essayé avec byref par ne pas réussir, toute aide est appréciée .. grâce

Répondre

1

L'instruction labs = [[NSMutableArray alloc] init]; fait labs pour pointer vers le nouveau tableau dans la portée de la méthode. Cela ne fait pas pointer le pointeur de l'appelant vers le nouveau tableau.

Si vous voulez changer le pointeur de l'appelant, faire quelque chose comme ceci:

// The caller 
NSMutableArray *labels;   // Don't initialize *labels. 
[self processLabels:&labels]; 

... 

- (void)processLabels:(NSMutableArray**)labs{ 
    *labs = [[NSMutableArray alloc] init]; 
    [*labs addObject:@"Random"]; 
    ... 
} 

C'est probablement une mauvaise idée car processLabels: attribue le tableau, mais l'appelant est responsable de sa libération.

Si vous voulez que l'appelant à posséder le tableau, vous pouvez écrire processLabels: comme ceci:

- (void)processLabels:(NSMutableArray*)labs{ 
    [labs removeAllObjects]; 
    [labs addObject:@"Random"]; 
    ... 
} 

Ou, si processLabels: est juste retourner une collection d'étiquettes:

- (NSMutableArray*)processLabels { 
    NSMutableArray* labs = [[[NSMutableArray alloc] init] autorelease]; 
    [labs addObject:@"Random"]; 
    ... 
    return labs; 
} 

Si vous voulez l'appelant à être responsable de la libération du tableau, supprimer la autorelease. Dans ce cas, la convention impose que le nom de la méthode commence par alloc ou new ou contienne le mot copy.

3

« laboratoires » doivent être initialisées avant de passer à processLabels, et il ne doit pas être réinitialisée .

Si vous ne pouvez pas initialiser le tableau à l'avance pour une raison quelconque et que vous voulez processLabels pour le créer, vous devez passer un pointeur vers un pointeur:

[self processLabels:&labels]; 

et la méthode changerait à:

- (void)processLabels:(NSMutableArray**)labs{ 
    *labs = [[NSMutableArray alloc] init]; 
    [*labs addObject:@"Random"]; 
.... 
} 
1

Vous devez passer dans un tableau mutable pour être en mesure de le changer (ce qui est la définition de Mutable) - pour transformer un NSArray dans un tableau mutable, utilisez:

NSMutableArray *writableArray = [NSMutableArray arrayWithArray:oldArray]; 

ou si vous voulez juste faire un vide tableau mutable.

NSMutableArray *writableArray = [NSMutableArray array]; 

passent ensuite que

2

parlé en général, il est préférable de ne pas transmettre les collections mutables, mais de fournir des méthodes qui effectuent des travaux sur eux ...

En fait, en réponse à votre code je me demande même quel est le but de passer le tableau 'labs' dans la fonction alors qu'en fait vous ne faites que l'écraser (et créer une fuite de mémoire dans le processus). Pourquoi faire ça?

+0

Je suis d'accord avec vous. Si vous avez un retour vide, pourquoi ne pas simplement retourner le tableau à la place? – Abizern

1

Est correct, à la fois sur la correction de la méthode existante, et sur ce qui est une mauvaise idée. Le retour à un paramètre de référence est certainement valide, et il est fréquemment utilisé dans les programmes C simples, mais dans ce cas, il ajoute une complexité inutile. En Objective-C, l'idiome préféré est de retourner les objets en utilisant d'abord la valeur de retour, et de ne stocker en retour vers un pointeur que si la valeur de retour est déjà utilisée pour retourner quelque chose d'autre. Non seulement cela rendra les appels à une méthode plus faciles à lire et à écrire, mais il se conforme aux idiomes standard qui sont couramment utilisés dans d'autres langages (tels que Java et C#). Il devient assez évident si vous écraser un pointeur de tableau en lui affectant, un bogue potentiel qui est plus susceptible d'être pris en charge par des outils tels que le Clang Static Analyzer. Sur une note connexe, vous devriez probablement également envisager une meilleure dénomination de méthode et de paramètre. (Je réalise que c'est probablement un exemple un peu artificiel.) Si vous traitez des "labels", et qu'ils proviennent d'une autre source que le tableau mutable que vous créez, je ne nommerais pas la variable locale "labs" ou " labels "- utilisez un nom plus descriptif. Les noms de méthodes qui sont moins vagues sur ce qu'ils font peuvent grandement améliorer la lisibilité du code. En Objective-C, les noms longs des méthodes descriptives sont préférés. Puisque Xcode termine le code et que les noms des méthodes sont moins ambigus, le résultat final est habituellement moins.