41 Stimmen

NSArray @property unterstützt durch ein NSMutableArray

Ich habe eine Klasse definiert, in der ich eine öffentliche Eigenschaft so darstellen möchte, als ob sie durch eine NSArray . Das ist einfach genug, aber in meinem Fall ist das eigentliche Backing Ivar ein NSMutableArray :

@interface Foo
{
    NSMutableArray* array;
}
@property (nonatomic, retain) NSArray* array;

@end

In meiner Implementierungsdatei ( *.m ) I @synthesize die Eigenschaft, aber ich stoße sofort auf Warnungen, weil die Verwendung self.words ist dasselbe wie der Versuch, eine NSArray .

Wie geht man dabei richtig vor?

Danke!

21voto

Mark Adams Punkte 30572

Ich würde eine Erklärung abgeben readonly NSArray in Ihrem Header und überschreiben Sie den Getter für dieses Array, um eine Kopie eines privaten NSMutableArray in Ihrer Implementierung deklariert. Betrachten Sie das Folgende.

Foo.h

@interface Foo

@property (nonatomic, retain, readonly) NSArray *array;

@end

Foo.m

@interface Foo ()

@property (nonatomic, retain) NSMutableArray *mutableArray

@end

#pragma mark -

@implementation Foo

@synthesize mutableArray;

- (NSArray *)array
{
    return [[self.mutableArray copy] autorelease];
}

@end

15voto

sam Punkte 3300

Grundsätzlich wird die NSArray-Eigenschaft in eine Kategorie in Ihrer Header-Datei und die Eigenschaft NSMutableArray in der Klassenerweiterung in Ihrer Implementierungsdatei. Zum Beispiel so...

Foo.h:

@interface Foo
@end

@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end

Foo.m

@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end

5voto

Tom Andersen Punkte 6956

Einfach:

1) Benutzen Sie keine Eigenschaft, wenn es keine ist.

2) Der Code vereinfacht sich zu:

- (NSArray *)currentArray {
    return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray -    otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it. 
}

- (void)setArray:(NSArray *)array {
    [mutableArray setArray:array];
}

Wenn das Objekt zugewiesen wird, erstellen Sie das Array, wenn es stirbt, geben Sie das Array frei.

Wenn große Effekte bei der bloßen Verwendung eines '.'-Operators auftreten, kann man leicht einen äußerst ineffizienten Code übersehen. Accessors sind genau das. Auch - wenn jemand aFoo.array aufruft - der Vertrag ist es, Zugriff auf die Array-Mitglieder von foo zu bekommen - aber wirklich ist es nur eine Kopie zum Zeitpunkt des Aufrufs. Der Unterschied ist real genug, dass er Fehler in den anderen hier geposteten Implikationen verursacht hat.

4voto

Rob Zombie Punkte 11705

Update: Diese Antwort ist nicht mehr gültig. Verwenden Sie eine der unten vorgeschlagenen Lösungen.

Heutzutage können Sie Folgendes tun:

Foo.m:

@implementation Foo {
    NSMutableArray* _array;
}

@end

Foo.h:

@interface Foo

@property (readonly, strong) NSArray* array;

@end

Sie können immer noch mutable _array durch ivar aus dem Inneren der Implementierung und außerhalb wird es über unveränderliche Eigenschaft zugänglich sein. Leider garantiert dies nicht, dass andere es nicht in NSMutableArray umwandeln und verändern können. Für einen besseren Schutz vor Idioten muss man eine Accessor-Methode definieren und eine unveränderliche Kopie zurückgeben, was jedoch in einigen Fällen sehr teuer sein kann.

Ich würde eigentlich mit einem der Kommentare oben zustimmen, dass es besser ist, einfache Accessor-Methoden zu verwenden, wenn Sie einige schreibgeschützte Daten zurückgeben müssen, es ist definitiv weniger zweideutig.

2voto

Regexident Punkte 29336

Das liegt daran, dass Ihre Eigenschaft mit dem Klassentyp des aktuellen Ivars übereinstimmen muss.

Eine mögliche Lösung/Workaround:

//Foo.h:
@interface Foo
{
    NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you're picky about wrapper-properties.
@end

//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end

@implementation

@synthesize mutableArray;
@dynamic array;

- (NSArray *)array {
    return [NSArray arrayWithArray:self.mutableArray];
}

- (void)setArray:(NSArray *)array {
    self.mutableArray = [NSMutableArray arrayWithArray:array];
}

@end

Sie fügen eine private mutableArray Eigenschaft in einer Klassenerweiterung und die öffentliche array einfach an Ihren privaten veränderbaren weiterleiten.

Mit den neuesten Spracherweiterungen von ObjC neige ich dazu, die

{
    NSMutableArray* mutableArray;
}

ivar-Block nach Möglichkeit vollständig zu entfernen.

Und definieren Sie den Ivar durch die Synthese als solche:

@synthesize mutableArray = _mutableArray;

die eine NSMutableArray *_mutableArray; Beispiel für Sie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X