2010-04-02 5 views
10

Il se peut que je manque quelque chose d'évident ici, mais j'implémente NSCopying sur l'un de mes objets. Cet objet possède des variables d'instance privées qui ne sont pas exposées via des getters, car elles ne doivent pas être utilisées en dehors de l'objet.Meilleure pratique pour copier des vars d'instances privées avec NSCopying

Dans mon implémentation de copyWithZone:, j'ai besoin de alloc/init pour la nouvelle instance, mais aussi de configurer son état pour qu'il corresponde à l'instance actuelle. Je peux évidemment accéder à l'état privé actuel depuis l'intérieur copyWithZone:, mais je ne peux pas le définir dans le nouvel objet, car il n'y a pas d'accesseurs pour cet état.

Existe-t-il un moyen standard de contourner ce problème tout en préservant la confidentialité des données?

Merci.

Répondre

8

D'abord, vous devriez toujours avoir getters, même si elles sont privées. Votre objet devrait seulement accéder à ses propres ivars en utilisant des accesseurs (sauf dans un très petit nombre de cas). Cela vous épargnera beaucoup de souffrance sur la gestion de la mémoire. Deuxièmement, la suggestion d'Alex d'utiliser -> est une approche standard, même si cela viole la règle des getters ci-dessus. Il y a un petit nombre d'exceptions à cette règle, et la copie en est une. Utiliser des setters privés ici est toujours raisonnable (et je le faisais de cette façon exclusivement), mais j'ai trouvé pour diverses raisons que l'utilisation de -> fonctionne souvent plus propre.

Faites très attention à la gestion de la mémoire. Si vous avez besoin d'appeler [super copyWithZone:], alors vous devriez également lire sur les complexités de NSCopyObject() et comment cela vous affecte même si vous ne l'utilisez pas vous-même. J'en ai discuté longuement dans "NSCopyObject() considered harmful."

+0

Merci pour la mention des accesseurs privés ainsi que les périls de NSCopyObject. –

+0

Je ne suis pas sûr de savoir comment avoir des accesseurs en lecture seule aide la gestion de la mémoire? Si vous ne l'utilisez pas avec 'assign' ou' retain', cela ne fait aucune différence que vous utilisiez getter ou la variable directement. – Hemant

+0

@Hemant, Parce que l'appelant ne devrait pas avoir besoin de faire attention à savoir si la propriété est actuellement (ou dans le futur) en lecture seule ou non. Ce n'est pas l'affaire de l'appelant, et cela pourrait changer au fil du temps, et alors vous auriez besoin de traquer chaque morceau de code qui l'a fait incorrectement. En respectant des règles simples, les erreurs deviennent évidentes. Quand vous dites "oh, sauf quand je sais que c'est actuellement correct" alors vous vous ouvrez pour des maux de tête d'entretien. –

5

Vous pouvez accéder directement aux variables d'instance de la copie. Vous utilisez la même syntaxe de déréférencement de pointeur que vous utiliseriez avec une structure. Ainsi, par exemple, si votre classe est la suivante:

@interface MyCopyableClass : NSObject { 
    int anInstanceVariable; 
} 
@end 

Vous pouvez le faire:

- (id)copyWithZone:(NSZone *)zone { 
    MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init]; 
    theCopy->anInstanceVariable = anInstanceVariable; 
    return theCopy; 
} 
1

Une option consiste à créer un initialiseur personnalisé qui accepte les valeurs iVar privées. Donc, vous le créez comme:

-(id) initWithPropertyOne:(SomeClass *) anObject andPropertyTwo:(SomeClass *) anotherObject; 

Lorsque vous instanciez la copie, utilisez simplement l'initialiseur personnalisé.

Questions connexes