Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
Properties, Teil 1

Seit dem Erscheinen von Objective-C 2.0 mit OS X 10.5 haben Sie die Möglichkeit Properties an Stelle von Accessor-Methoden zu verwenden. Properties sind dabei eine Art virtuelle Accessor-Methoden, denn an der ursprünglichen Benutzbarkeit der Klasse ändert sich nichts. Der Compiler kümmert sich im Hintergrund um alles.

In der Praxis sind Properties eine große Arbeitserleichterung. Die Person.h reduziert sich auf wenige Zeile Code.
#import <Cocoa/Cocoa.h>

@interface Person : NSObject {
    NSString *name;
    NSString *vorname;
    NSNumber *alter;
}

@property(retain) NSString *name;
@property(retain) NSString *vorname;
@property(retain) NSNumber *alter;

@end
Und die Person.m ist nahezu leer.
#import "Person.h"

@implementation Person

@synthesize name;
@synthesize vorname;
@synthesize alter;

@end
Hierbei kann man @property als Deklaration verstehen und durch @synthesize werden die Accessor-Methoden vom Compiler implementiert.

Wie aber wird diese Klasse und diese Instanzvariablen verwendet? Nicht anders als Sie es gewohnt sind. Es ist die gleiche Schreibweise wie bei normalen Accessor-Methoden.
#import <Foundation/Foundation.h>
#import "Person.h"

int main (int argc, const char* argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Person *myPerson = [[Person alloc] init];
    [myPerson setAlter:[NSNumber numberWithInt:
32] ];
    [myPerson setName:
@"Müller"];
    [myPerson setVorname:
@"Max"];

    NSLog(
@"Name: %@",[myPerson name]);
    NSLog(
@"Alter: %@",[myPerson alter]);
    NSLog(
@"Vorname : %@",[myPerson vorname]);

    [pool drain];
    return 0;
}
Wie Sie sehen erfolgt der Zugriff weiterhin durch name und setName. Genau so, als ob Accessor-Methoden vorhanden wären. Die Getter-Methode ist identisch mit dem Variablennamen. Während die Setter-Methode sich immer aus „set“ und Variablennamen zusammensetzt.
stacks_image_10844FD8-4741-4B57-BCF2-CF3EFE808471
Ausser dem verminderten Programmieraufwand bieten Properties einen weiteren Vorteil. Sie ermöglichen die Verwendung der Punkt-Notation (eng. dot-notation), einer anderen Schreibweise, die Sie vielleicht schon aus anderen Programmiersprachen kennen. Im Code sieht das dann so aus:
#import <Foundation/Foundation.h>
#import
"Person.h"

int main (int argc, const char* argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Person *myPerson = [[Person alloc] init];

    myPerson.alter = [NSNumber numberWithInt:
32];
    myPerson.vorname =
@"Max";
    myPerson.name =
@"Müller";

    NSLog(
@"Name: %@",myPerson.name);
    NSLog(
@"Vorname: %@",myPerson.vorname);
    NSLog(
@"Alter : %@",myPerson.alter);

    [pool drain];
    return 0;
}
Sie haben also die Wahl zwischen der Punkt-Notation oder der traditionellen Schreibweise. Vom Ergebnis her gibt es keine Unterschiede, beide Funktionsweisen funktionieren gleich gut. Properties gibt es aber erst ab Objective-C 2.0 also seit OS X 10.5. Vergessen Sie das, nicht falls Sie für ältere Systeme kompatibel programmieren wollen oder müssen.

Wie Ihnen vielleicht aufgefallen ist, wurden die Properties mit einem Attribut, nämlich retain, deklariert. Dieses Schlüsselwort bestimmt das Verhalten und den Zugriff. Ersetzen sie retain durch readonly, wird für dieses Property keine Setter-Methode erzeugt.
@property(readonly) NSString *name;
Es gibt weitere Attribute, wie zum Beispiel copy oder assign. Die Verwendung von retain bedeutet, dass kein Wert, sondern nur ein Speicherzeiger übergeben wird. Ändert sich der originale Wert, änderte sich auch der Wert in der Klasse. Die Verwendung von copy verhindert das, indem es eine Kopie erstellt. So ein Verhalten ist aber in den seltensten Fällen gewünscht.

Der Parameter readonly bedeutet natürlich nicht, das keine Instanzvariable mehr erzeugt wird. Sie können nur nicht mehr von ausserhalb der Klasse darauf zugreifen, da die Getter-Methode fehlt. Innerhalb der Klasse habe Sie natürlich weiterhin vollen Zugriff.
-(void)doSomething
{
    self->name = @"Holger";
}
Diese fehlende Getter-Methode können Sie natürlich jederzeit selbst hinzufügen, indem Sie den nötigen Code schreiben. Es ist durchaus legitim beide Möglichkeiten miteinander zu kombinieren. Sobald Sie für eine Instanzvariable Getter oder Setter selbst implementieren, wird der Compiler keine Methoden mehr dafür generieren.

Es gibt auch eine Möglichkeit den Compiler explizit davon abzuhalten, für ein Property Accessor-Methoden zu generieren. Verwenden Sie statt @synthesize den Befehl @dynamic. Jetzt sind Sie in der Pflicht, eine, oder beide Methoden zu schreiben.

Properties auf andere Instanzvariablen

Durch die Verwendung von @property und @synthesize können Sie sehr schnell und bequem Instanzvariablen mit entsprechenden Accessor-Methoden ausstatten. Dabei besagt die Namenskonvention, dass Accessor-Methoden immer so heissen, wie die Variablen. Das muss nicht zwangsläufig so sein, Sie können den Property-Namen auch selbst festlegen.
@interface Person : NSObject {
    NSString *fName;
}

@property(retain) NSString *firstName;

@end
Diese Headerdatei enthält eine Variable fName und ein Property firstName. Soll nun firstName ein Accessor für fName werden, geschieht dies über die @synthesize Anweisung.
@synthesize firstName = fName;
Während fName weiterhin als Variable fungiert, aber „private“ ist, dient firstName als Bezeichner für die Accessor-Methoden.
myPerson.firstName = @"Hans Herbert";
NSLog(myPerson.firstName);
Und in der konventionellen Schreibweise:
[myPerson setFirstName:@"Hans Herbert"];
NSLog([myPerson firstName]);
Properties mit eigenen Accessoren

Um es auf die Spitze zu treiben, können Sie auch die Namenskonvention für Accessor-Methode überschreiben und eigene Namen für Getter und Setter verwenden.
@property(setter=nameSchreiben:,getter=nameLesen,retain) NSString *name;
Der Zugriff erfolgt dann so:
[myPerson nameSchreiben:@"Hans Müller"];
NSLog([myPerson nameLesen]);
Hier gilt wieder die goldenen Regel der Softwareentwicklung: Nicht alles was technisch machbar ist, ist auch sinnvoll. Ob man eigene Namen für Accessor-Methoden braucht, ist fraglich. Für die Lesbarkeit des Programmcodes ist es jedenfalls nicht umbedingt vorteilhaft.

Properties auf Methoden

Eine weitere Einsatzmöglichkeit der Properties ist eine Anwendung, nicht auf Instanzvariablen, sondern auf Methoden.
@property(readonly) NSString* zusammenfassung;
Was hier wie eine Variable aussieht, ist in der Implementation eine Methode. In diesem Fall fällt die @synthesize Anweisung natürlich weg und das Property ist erwartungsgemäß readonly.
- (NSString*)zusammenfassung
{
    return[NSString stringWithFormat:@"%@ %@ ist %@ Jahre alt.",
     self.vorname, self.name, self.alter];
}
Auch hier kann wieder die Punkt-Notation benutzt werden.
NSLog(myPerson.zusammenfassung);
stacks_image_9D74A905-0003-4C70-98C3-87BBD6CAFA1A