Properties in ObjectiveC
Ingo / 2. Dez 2009, 16:18 Uhr.
Gespeichert in: Grundlagen
Properties sind in ObjectiveC eigentlich nichts anderes, als ein definierter Satz an Methoden. Die Methodennamen folgen dabei folgendem Konzept:
- (<Datentyp>) <propertyName>; // zum Auslesen des Wertes propertyName- (void) set<PropertyName>:(<Datentyp>)var; // zum Setzen des Wertes propertyNameHier mal ein Beispiel, wie man Methoden bereitstellen würde, um auf die Instanzvariable
int meineZahl; zuzugreifen:- (int) meineZahl {
return meineZahl;
}
- (void) setMeineZahl:(int)var {
meineZahl = var;
}Natürlich ist das nur die einfachste Variante, wie man Propertymethoden bauen kann. Man kann in solchen Methoden den ganzen Unfug machen, den man auch in normalen Methoden machen kann. So könnte man z.B. Retain und Release beachten, wenn man über die set-Methode (auch Setter genannt) ein Objekt setzt:
- (void) setMeinString:(NSString*)var {
[var retain];
[meinString release];
meinString = var;
}Und jetzt erkennt man auch schon den Vorteil von Properties: Man muss sich in seinem Programm nicht mehr über das Variablenhandling Gedanken machen, wenn man die Variablen nutzen will. Das erledigen die Propertymethoden.
Um aber statt direkt auf die Variablen zuzugreifen nun über die Property zu gehen, kann man klassisch die Methoden benutzen, z.B.
[meinObjekt setMeinString:@"Hallo Welt"]; // Setzt den Wert @"Hallo Welt"meinObjekt.meinString = @"Hallo Welt"; // Setzt den Wert @"Hallo Welt"meinObjekt.meinString.Und es gibt auch eine Hilfe, um Propertymethoden zu erstellen; das kann ObjectiveC nämlich alleine!
@interface MeineKlasse : NSObject {
NSString* meinString;
}
@property (retain) NSString* meinString;
@end@synthesize meinString;Das ist eigentlich auch schon die ganze Propertyzauberei. Neben der Option
retain gibt es noch ein paar weitere Optionen, die man in den Klammern durch Kommata getrennt angeben kann, wodurch die Properties erst ihre ganze Stärke ausspielen können:readonly: Es wird nur ein Getter erzeugt, kein Setter.
readwrite: Es wird Getter und Setter erzeugt. Dies ist die Standardeinstellung.
assign: Der übergebene Wert wird direkt zugewiesen. Dies ist die Standardeinstellung.
retain: Nur bei Objekten anwendbar. Retain und Release wird beachtet.
copy: Nur bei Objekten anwendbar. Das Objekt wird komplett kopiert, nicht nur der Zeiger gemerkt.
nonatomic: Normalerweise kümmern sich Getter und Setter darum, dass der Zugriff auf die Instanzvariablen möglichst "robust" ist, z.B. wenn mehrere Threads konkurrierend auf einen Getter oder Setter zugreifen. Diese Option schaltet diesen robusten Zugriff ab.
6 Kommentare
|
Permalink
|
Trackback-Info
Operatoren, Teil 3
Ingo / 4. Okt 2009, 12:47 Uhr.
Gespeichert in: Grundlagen
Hier also nun eine Liste von Operatoren in der Reihenfolge, in der sie abgearbeitet werden. Operatoren mit höherer Priorität stehen also weiter oben.
Operatoren, die sich in der gleichen Gruppe befinden sind dabei gleichwertig und werden einfach der Reihe nach abgearbeitet. Je nach Gruppe und Funktion des Operators geschieht dies innerhalb der Gruppe von links nach rechts oder von rechts nach links:
| Gruppe | Operatoren | Beschreibung | Auswertungsrichtung |
|---|---|---|---|
| 1 | . | Zugriff auf Properties eines Objekts | von links nach rechts |
| ++ -- | Inkrement/Dekrement nach einer Variablen | ||
| 2 | ! ~ | logisches, binäres NOT | von rechts nach links |
| + - | als Vorzeichen | ||
| ++ -- | Inkrement/Dekrement vor einer Variablen | ||
| 3 | * / % | Arithmetische Operatoren | von links nach rechts |
| 4 | + - | Arithmetische Operatoren | von links nach rechts |
| 5 | << >> | Schiebe-Operatoren | von links nach rechts |
| 6 | < <= > >= | Vergleichsoperatoren | von links nach rechts |
| 7 | == != | Vergleichsoperatoren | von links nach rechts |
| 8 | & | UND Bitoperator | von links nach rechts |
| 9 | ^ | EXKLUSIV OR Bitoperator | von links nach rechts |
| 10 | | | OR Bitoperator | von links nach rechts |
| 11 | && | logischer UND Operator | von links nach rechts |
| 12 | || | logischer ODER Operator | von links nach rechts |
| 13 | = | Zuweisungsoperatoren | von rechts nach links |
| *= /= %= | |||
| += -= | |||
| &= ^= |= | |||
| <<= >>= | |||
| 14 | , | Komma/Liste-Operatoren | von links nach rechts |
Operatoren, Teil 2
Ingo / 11. Sep 2009, 14:39 Uhr.
Gespeichert in: Grundlagen
true und false.Binäre Operatoren (Bitweise Operatoren)
Binäre Operatoren verknüpfen Ganzzahlen auf Bitebene miteinander. Die betroffene Ganzzahl (z.B. vom Typint) muss man sich dabei am besten in binärer Form entsprechend dem Dualsystem vorstellen. Zu dem beispielhaften Code unten ist noch zu sagen, dass es in C-Dialekten keine Möglichkeit gibt, um Binärzahlen direkt darzustellen. Die 0100010-Folgen sind also nur symbolisch zu betrachten und stehen für ihre dezimalen Derivate.0101010 & 1101100 == 0101000 // Boolesche UND-Verknüpfung
0101010 | 1101100 == 1101110 // Boolesche ODER-Verknüpfung
0101010 ^ 1101100 == 1000110 // Boolesche EXKLUSIV-ODER-Verknüpfung
~ 1101100 == 0010011 // Boolesche NICHT-Verknüpfung
0001000 << 2 == 0100000 // Bitverschiebung nach links (hier um 2 Bits)
0001000 >> 2 == 0000010 // Bitverschiebung nach rechts (hier um 2 Bits)Wir sparen es uns hier zu erklären, was denn der gute Herr Boole sich für Gedanken bzgl. der Veknüpfung zweier möglicher Zustände gedacht hat. Wenn Dir jedoch die Bedeutung boolescher Operatoren nicht bekannt ist, dann kannst Du sie unter "Bitweise Operatoren" in der Wikipedia nachschlagen. Die Wikipedia kann das in diesem Fall nämlich sehr gut und sehr ausführlich erklären!
Boolesche Operatoren (Logische Operatoren)
Boolesche Operatoren funktionieren im Prinzip genau wie die booleschen Versionen ihrer binären Verwandten, die oben aufgeführt sind. Jedoch betrachten sie die gegebenen Zahlen nicht als Bitfeld, sondern wandeln sie im Gesamten zutrue oder false um. Jeder Wert, außer der "0", wird dabei zu true.true && false == false // Boolesche UND-Verknüpfung
42 && 1 == true // ist true, weil 42 und 1 ungleich 0 sind
true || false == true // Boolesche ODER-Verknüpfung
! true == false // Boolesche NICHT-VerknüpfungEs ist zu beachten, dass es keinen EXKLUSIV-ODER Operator gibt, wie bei den Binären Operatoren!
Aber: Was nutzen uns die Booleschen Überlegungen? Wir können sie z.B. ganz hervorragend für Kontrollstrukturen einsetzen! Man kann so mehrere Bedingungen durch ein
if abfragen:if (a>0 && b>0) {wenn a UND b größer 0 sind, wird dieser Code ausgeführt}
if (a>0 || b>0) {wenn a ODER b größer 0 sind, wird dieser Code ausgeführt}Hiermit haben wir die wichtigsten Operatoren angesprochen. In Operatoren, Teil 3 behandeln wir der die Reihenfolge, in der die Operatoren ausgeführt werden. Dies geschieht nämlich genau wie in der Mathematik nicht einfach von links nach rechts (Stichwort: "Punkt- vor Strichrechnung"), sondern geschieht FÜR ALLE Operatoren in einer festgelegten, sinnvollen Reihenfolge.
Retain, Release und Autorelease
Ingo / 30. Aug 2009, 11:38 Uhr.
Gespeichert in: Grundlagen
string2 = string1), dann wird in Wirklichkeit nur der Zeiger kopiert. Beide Variablen verweisen auf das gleiche Objekt.Das hat nachhaltige Folgen. Schickt man Methoden an das Originalobjekt, dann wirkt sich das genauso auf den zweiten "Zeiger" aus und umgekehrt, genau wie bei einer Datei auf der Festplatte und einem Alias (unter Windows auch 'Verknüpfung' genannt).
Was passiert also, wenn ein Programmteil ein Objekt per
release freigibt (siehe Artikel Objekte erstellen) und ein anderer Programmteil greift nun doch nochmal über einen anderen Zeiger auf das Objekt zu? Das Programm stürzt gnadenlos ab!Um dieses Problem zu umgehen, hat man in Cocoa die Möglichkeit geschaffen einem Objekt zu sagen, dass man es noch benötigt. Gibt dann ein anderer Programmteil das Objekt per
release frei, wird es nicht wirklich freigegeben. Es wird erst freigegeben, wenn alle beteiligten Programmteile per release bestätigt haben, dass sie das Objekt nicht mehr benötigen. Die Objekte zählen intern mit, wie oft sie benötigt werden. Den "Anspruch" auf ein Objekt meldet man mit retain an:NSString* string2; // Einen neuen Zeiger definieren
string2 = string1; // Eine Kopie des Zeigers 'string1' anfertigen
[string2 retain]; // Dem System mitteilen, dass wir 'string2' eine Weile benötigen
[mach_was_sinnvolles];
[string2 release]; // wir geben das Objekt wieder freiNochmals zur Verdeutlichung: Man kann das
retain oder release oben auch an string1 schicken. Es handelt sich ja um das gleiche Objekt, nur unter einem anderen Namen!Wie man sicher schnell erkennt, macht ein
retain auf ein Objekt meistens nur Sinn, wenn es über mehrere Methoden hinweg erhalten bleiben soll. Innerhalb eines einzelnen Codeblocks kann ich ja schließlich auch den ersten Zeiger benutzen. Hierzu seht ihr in unserem Videocast mehr! Wir behandeln das Thema Speicherverwaltung ausführlich ab der Folge '#007: Speicher, Zeiger und Objekte'.Alle Methoden, die mit
init oder copy beginnen, machen übrigens automatisch ein retain. Hier ist also zum Ende der Benutzung nur noch ein release notwendig.Auch wenn man ein Objekt als Parameter an ein anderes Objekt übergibt, dann muss sich der "Empfänger" selbst darum kümmern, ob er das Objekt noch eine Weile braucht, zum Beispiel wenn man einen String an ein NSTextField übergibt. Man muss also nicht für andere Objekte mitdenken:
[meinTextFeld setStringValue:string1];
// Hier muss man nicht für das Textfeld mitdenken.
// Das Textfeld macht selbst ein retain auf string1, wenn es den String behalten will.Weiss man zu Beginn einer Codeblocks bereits, dass man ein selbsterstelltes Objekt nur kurzfristig benötigt, dann kann man auch die Funktion
autorelease benutzen und es damit dem System überlassen, dass dem Objekt irgendwann nach Beendigung des aktuellen Codeblocks ein release geschickt wird:Manchmal ist es erwünscht, dass man doch eine komplett neue Kopie eines Objektes erhält, die somit auch nicht mehr mit dem Originalobjekt in Verbindung steht. Hierzu gibt es die Methode
copy. Diese Methode kopiert eimal das komplette Objekt in einen neuen Speicherbereich und führt auch schon ein retain aus:NSString* string1 = @"Hallo Welt!";
NSString* string2 = [string1 copy];
// Erzeugt eine Kopie von string1. Es gibt also nun zwei Objekte.
// Entsprechend wird auch doppelt so viel Speicherplatz verbraucht.Mit
retain und release muss man sehr gut aufpassen! Ein retain zuviel, schon wird der Speicherbereich nicht mehr freigegeben. Ein release zuviel, schon stürzt das Programm ab!
Objekte erstellen
Ingo / 30. Aug 2009, 11:37 Uhr.
Gespeichert in: Grundlagen
NSString* string1; // einen Zeiger vom Typ NSString erstellen
string1 = [NSString alloc]; // Speicher für den NSString reservieren
[string1 init]; // Das Objekt initialisierenIm Normalfall schreibt man alles in eine Zeile und verschachtelt
alloc und init. Folgende Zeile hat also den gleichen Effekt:Hierfür gibt es zusätzlich nochmal eine Kurzform, die den gleichen Effekt hat:
Nun macht die obige Zeile im Fall von NSString wenig Sinn. Man kann NSString nämlich nach dem init nicht mehr verändern, also keine Zeichenkette mehr zuweisen (im Gegensatz zur Klasse NSMutableString). Daher haben solche Objekte erweiterte init-Methoden, die eine zusätzliche Parameter-Übergabe erlauben, um zum Beispiel einen NSString mit einem Wert zu befüllen. Alle init-Methoden finden sich zu jeder Klasse in der Dokumentation in Xcode. Hier ein Beispiel:
Hier wird ein String mit einem anderen String (@"Hallo Welt") befüllt. Nochmal zur Erinnerung: Das ist nur ein Beispielkonstrukt. Das @-Zeichen vor einem doppelten Anführungszeichen ist ein sogenanntes Makro; also eine Kurzform zur Erstellung eines Strings. Da man String-Objekte sehr häufig benötigt, wurde dieses Makro eingeführt. Letztendlich erzeugt das @-Zeichen bereits einen NSString. Davon wird oben dann ein weiterer String erstellt, also eine Kopie.
Wenn man den String nicht mehr benötigt, dann sollte man nicht vergessen den Speicher wieder freizugeben:
[string1 release];Das Retain- und Release Konzept von Cocoa ist ein eigenes, großes Thema. Wir haben das in unserem Videocast, beginnend mit der Folge '#007: Speicher, Zeiger und Objekte' thematisiert. Zusätzlich gibt es den Grundlagenartikel Retain, Release und Autorelease.
Operatoren
Ingo / 2. Aug 2009, 09:34 Uhr.
Gespeichert in: Grundlagen
Zuweisungs- und Rechenoperatoren (Arithmetische Operatoren)
Einer der häufigsten Operatoren dürfte der Zuweisungsoperator sein, das Gleicheitszeichen. Links vom Gleichheitszeichen steht immer eine Variable. Der Variablen versucht der Computer das zuzuweisen, was rechts vom Gleichheitszeichen steht:x = 1; // Die Variable x erhaelt den Wert 1
y = x + 1; // Die Variable y erhaelt den Wert 2 nach Addition
z = y * 2; // Die Variable z erhaelt den Wert 4 nach Multiplikation
z2 = (y+1) / 3; // Die Variable z2 erhaelt den Wert 1 nach Addition und DivisionHier haben wir jetzt die vier Grundrechenarten kennengelernt. Sie funktionieren genau wie in der Mathematik. Da auch beim Computer Punkt- vor Strichrechnung geht, habe ich im letzten Beispiel das (y-1) geklammert, damit erst 1 subtrahiert wird und das Ergebnis dieser Subtraktion durch 3 dividiert wird. Letztendlich haben sogar alle Operatoren eine festgelegte Reihenfolge, in der sie abgearbeitet werden. So wird ja z.B. die Zuweisung immer erst durchgeführt, wenn alles rechts von ihr berechnet wurde.
Zusätzlich gibt es noch den Operator %, der den Rest einer Division bestimmt. 5 % 2 ist also 1.
In einem richtigen Programm muss man alle zu benutzenden Variablen natürlich vorher definieren, wie unter Datentypen beschrieben!
Vergleichsoperatoren
Manchmal muss man in Erfahrung bringen, ob zwei Werte gleich sind, oder vielleicht auch größer oder kleiner. Hier kommen die Vergleichsoperatoren ins Spiel. Das Ergebnis ist für den Computer immer wahr oder falsch, auf englisch true oder false. Für den Computer letztendlich bloß 1 oder 0.Hier seht ihr nun auch das erste Mal Operatoren, die aus mehr als einem Zeichen bestehen. Nehmen wir mal an, die Variablen von oben haben noch die dort berechneten Werte, dann weisen wir das Vergleichsergebnis nun jeweils der Variablen e zu. Zuerst wird dabei immer der Vergleich rechts vom = durchgeführt und anschließend e entweder 1 (also wahr) oder 0 (also falsch) zugewiesen.
e = x < y; // ist x kleiner y? Ergebnis ist 1, also wahr
e = x > z; // ist x groesser z? Ergebnis ist 0, also falsch
e = x >= z2; // ist x groesser oder gleich z2? Ergebnis ist 1
e = x <= z2; // ist x kleiner oder gleich z2? Ergebnis ist 1
e = x != z2; // ist x ungleich z2? Ergebnis ist 0
e = x == z2; // ist x gleich z2? Ergebnis ist 1Achtung! Der letzte Vergleich beinhaltet eine Falle, über die Anfänger gerne mal stolpern! Es gibt die beiden Operatoren = und ==! Der Erste, das =, ist immer eine Zuweisung, der Zweite, das ==, immer ein Vergleich! Vertut man sich hier, dann kann es zumindest für Anfänger zu überraschenden Ergebnissen kommen, da auch eine Zuweisung ein Ergebnis hat, dass sich mit true oder false umschreiben lässt... dazu aber an anderer Stelle mehr.
Es gibt noch einen großen Haufen weiterer Operatoren. Diese werden in in zusätzlichen Postings besprochen. Weiter gehts daher im Beitrag Operatoren, Teil 2!
Datentypen
Ingo / 14. Jul 2009, 23:12 Uhr.
Gespeichert in: Grundlagen
Programmiersprachen kennen daher sogenannte Datentypen und Standarddatentypen. Diese werden für uns Programmierer als Variablen dargestellt, genau wie in der Mathematik. Und genau wie in der Mathematik muss man in C-Dialekten auch einmal festlegen ("definieren"), ob eine Variable nun eine reelle Zahl, eine Ganzzahl, eine Zeichenkette oder was immer beinhaltet. Dann weiß der Computer auch, wie er die Nullen und Einsen zu interpretieren hat.
Sowas sieht in einem Computerprogramm so aus:
// Eine Datentypdefinition beginnt immer mit einem Schluesselwort.
// Dieses Schluesselwort stellt den Datentyp der Variable dar.
// Es folgt ein Variablenname, abgeschlossen durch ein Semikolon.
// Mit einem "//" leitet man einen Kommentar wie diesen hier ein.
// Kommentare werden vom Computer komplett ignoriert.
int x; // "int" bedeutet Integer, also "Ganzzahl", x ist der Variablenname
int meinezahl; // Hier heisst die Variable "meinezahl"
float y; // "float" bedeutet Fliesskommazahl, y ist der VariablennameDurch diese Befehle reserviert der Computer also genug RAM, um die jeweiligen Zahlentypen zu speichern. Ab sofort kann man dort Werte hineinschreiben oder damit rechnen:
x = 1; // Der Variablen x wir der Wert 1 zugewiesen
meinezahl = x + 41; // meinezahl hat nach diesem Befehl den Wert 42
x = x + 1; // x ist nun um eins groesser, als vorherWie man hier sieht, wird jeder in sich geschlossene Befehl mit einem Semikolon abgeschlossen. Das gehört zur sogenannten Syntax, der Grammatik einer Programmiersprache. So wie wir einen Punkt hinter einen Satz machen, so benötigt man in der Programmiersprache "C" ein Semikolon hinter einem Befehl, damit der Computer ihn versteht.
Zur Syntax gehört auch, dass man sich nicht beliebige Variablennamen ausdenken darf. Variablen müssen immer mit a-z, A-Z oder einem Unterstrich beginnen, dürfen dann jedoch zusätzlich Zahlen enthalten, aber keine Leerzeichen oder Rechenoperatoren. Selbstverständlich dürfen Variablen auch nicht identisch sein mit bereits vorhandenen Schlüsselwörtern.
Es gibt noch viel mehr Datentypen in C. Diese werdet ihr aber erst nach und nach kennenlernen. Gleiches gilt für die hier schon teilweise benutzten Operatoren. Es ist jetzt erstmal viel spannender, wie man etwas auf dem Bildschirm ausgibt und wo man solche Befehle überhaupt hinschreibt. Schließlich hat man nichts davon, wenn der Computer superschnell rechnet, aber wir das Ergebnis gar nicht sehen können.