Gibt es in Objective-c einen Unterschied zwischen einer „Instanzvariablen“ und einer „Eigenschaft“?

82

Gibt es einen Unterschied zwischen einer "Instanzvariablen" und einer "Eigenschaft" in Objective-c?

Da bin ich mir nicht ganz sicher. Ich denke, dass eine "Eigenschaft" eine Instanzvariable ist, die Zugriffsmethoden hat, aber ich könnte falsch denken.

Vielen Dank
quelle

Antworten:

84

Eine Eigenschaft ist ein abstrakteres Konzept. Eine Instanzvariable ist buchstäblich nur ein Speichersteckplatz, wie ein Steckplatz in einer Struktur. Normalerweise sollten andere Objekte niemals direkt darauf zugreifen. Eine Eigenschaft hingegen ist ein Attribut Ihres Objekts, auf das zugegriffen werden kann (es klingt vage und soll es auch sein). Normalerweise gibt eine Eigenschaft eine Instanzvariable zurück oder legt diese fest, kann jedoch Daten von mehreren oder gar keinen verwenden. Beispielsweise:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(Hinweis: Der obige Code ist insofern fehlerhaft, als er davon ausgeht, dass der Name bereits vorhanden ist und mindestens zwei Komponenten enthält (z. B. "Bill Gates" und nicht nur "Gates"). Ich hatte das Gefühl, dass das Korrigieren dieser Annahmen den eigentlichen Sinn des Codes ausmachen würde weniger klar, deshalb weise ich hier nur darauf hin, damit niemand diese Fehler unschuldig wiederholt.)

Futter
quelle
4
Die Art und Weise, wie ich Eigenschaften angezeigt habe, ist ein Mittel zum Bereitstellen / Einschränken des Zugriffs auf die Instanzvariablen für externe Objekte. Ein bisschen wie das öffentliche / private Konzept in anderen Sprachen?
Prototyp
"Normalerweise sollen andere Objekte niemals direkt darauf zugreifen" Was meinst du damit? Wird Ihre Antwort auch mit modernem Objective-C aktualisiert?
Honig
1
@Honey Ich denke, er bezieht sich auf das Konzept der Kapselung und befolgt Best Practices. Andere Objekte sollten nicht direkt auf den ivar zugreifen oder ihn ändern können. Durch die Steuerung des ivar-Zugriffs über Eigenschaften können wir diese Aufrufe abfangen, bevor sie sich möglicherweise auf den ivar auswirken. Weitere Informationen finden Sie hier: en.wikipedia.org/wiki/Encapsulation_(computer_programming)
user3344977
33

Eine Eigenschaft ist eine benutzerfreundliche Methode zum Implementieren eines Getters / Setters für einen bestimmten Wert mit zusätzlichen nützlichen Funktionen und Syntax. Eine Eigenschaft kann durch eine Instanzvariable gesichert werden, Sie können jedoch auch den Getter / Setter definieren, um etwas Dynamischeres zu tun. Sie können beispielsweise eine LowerCase-Eigenschaft für eine Zeichenfolge definieren, die das Ergebnis dynamisch erstellt, anstatt den Wert eines Elements zurückzugeben Variable.

Hier ist ein Beispiel:

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

Die @propertyZeile definiert eine Eigenschaft namens propertyNametype NSString *. Dies kann mit der folgenden Syntax abgerufen / festgelegt werden:

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

Wenn Sie zuweisen oder daraus lesen, myObject.propertyNamerufen Sie wirklich Setter / Getter-Methoden für das Objekt auf.

Die @synthesizeZeile weist den Compiler an, diese Getter / Setter für Sie zu generieren, indem die Mitgliedsvariable mit demselben Namen der Eigenschaft zum Speichern des Werts verwendet wird (oder otherVarNamewenn Sie die Syntax in Kommentaren verwenden).

Zusammen mit können @synthesizeSie dennoch einen der Getter / Setter überschreiben, indem Sie Ihren eigenen definieren. Die Namenskonvention für diese Methoden gilt setPropertyName:für den Setter und propertyName(oder getPropertyNamenicht Standard) für den Getter. Der andere wird weiterhin für Sie generiert.

In Ihrer @propertyZeile können Sie eine Reihe von Attributen in Parens für die Eigenschaft definieren, die Dinge wie Thread-Sicherheit und Speicherverwaltung automatisieren können. Standardmäßig ist eine Eigenschaft atomar, was bedeutet, dass der Compiler @synthesizget get / set-Aufrufe mit geeigneten Sperren umschließt, um Parallelitätsprobleme zu vermeiden. Sie können das nonatomicAttribut angeben , um dies zu deaktivieren (z. B. auf dem iPhone, für das Sie die meisten Eigenschaften standardmäßig verwenden möchten nonatomic).

Es gibt 3 Attributwerte, die die Speicherverwaltung für alle @synthesizedSetter steuern . Die erste retainwird automatisch releasean alte Werte der Eigenschaft und retainan die neuen Werte gesendet. Das ist sehr nützlich.

Die zweite copyMöglichkeit besteht darin, eine Kopie aller übergebenen Werte zu erstellen, anstatt sie beizubehalten. Es wird copyempfohlen, NSString zu verwenden, da ein Anrufer einen NSMutableString übergeben und unter Ihnen ändern kann. copyerstellt eine neue Kopie der Eingabe, auf die nur Sie Zugriff haben.

Das dritte ist assigndas Zuweisen eines geraden Zeigers, ohne das alte oder neue Objekt zum Zurückhalten / Freigeben aufzurufen.

Zuletzt können Sie das readonlyAttribut auch verwenden , um den Setter für die Eigenschaft zu deaktivieren.

Mike Weller
quelle
1
Hat das Deklarieren der Instanzvariablen und der Eigenschaft (z. B. propertyName) einen Vorteil? Die Deklaration innerhalb der Schnittstelle wird nicht benötigt, wenn Sie eine Eigenschaft für dieselbe Variable deklarieren, richtig? Dies spart wirklich Codezeilen, es sei denn, ich vermisse etwas.
Whyoz
6

Ich verwende Eigenschaften für den Schnittstellenteil - wo die Objektschnittstellen mit anderen Objekten und Instanzvariablen Dinge sind, die Sie in Ihrer Klasse benötigen - niemand außer Ihnen soll diese sehen und bearbeiten.

Jens Busch
quelle
3

Standardmäßig wird eine readwrite-Eigenschaft von einer Instanzvariablen unterstützt, die vom Compiler automatisch wieder synthetisiert wird.

Eine Instanzvariable ist eine Variable, die existiert und ihren Wert für die Lebensdauer des Objekts behält. Der für Instanzvariablen verwendete Speicher wird beim ersten Erstellen des Objekts (durch Zuweisung) zugewiesen und beim Freigeben des Objekts freigegeben.

Sofern Sie nichts anderes angeben, hat die synthetisierte Instanzvariable denselben Namen wie die Eigenschaft, jedoch mit einem Unterstrichpräfix. Für eine Eigenschaft namens firstName heißt die synthetisierte Instanzvariable beispielsweise _firstName.

jitenagarwal19
quelle
2

Früher nutzten Benutzer Eigenschaften öffentlich und ivars für den privaten Gebrauch. Seit einigen Jahren können Sie jedoch auch Eigenschaften definieren @implementation, um sie privat zu nutzen. Aber ich würde immer noch ivars verwenden, wenn es möglich ist, da weniger Buchstaben eingegeben werden müssen und es laut diesem Artikel schneller läuft . Dies ist sinnvoll, da Eigenschaften "schwer" sein sollen: Auf sie soll entweder von generierten Getter / Setter oder von manuell geschriebenen Getter zugegriffen werden.

In neueren Codes von Apple werden Ivars jedoch nicht mehr verwendet. Ich denke , weil es mehr wie objcnicht C/C++, und es ist einfacher , Eigenschaften zu verwenden , mit assign, nullableetc.

superarts.org
quelle
Ich vermute, dass Apples Verwendung von Eigenschaften in @implementationÄhnlichkeiten mit Swift zeigen möchte. Trotzdem bevorzuge ich es auch, Variablen zu sichern, um keinen virtuellen Funktionsaufruf zu verschwenden, um ein einfaches Feld meiner eigenen Klasse nachzuschlagen (und das passiert, wenn auf die Eigenschaft zugegriffen wird).
Leo