Objective-C und das Cocoa-Framework/ Objective-C/ Variablen und Funktionen

Aus Wikibooks

Wechseln zu: Navigation, Suche

Wir kommen nun zu etwas abstrakterem Wissen. Auch hier gilt wieder: Alles ausprobieren!
Objective-C basiert auf der ziemlich alten Programmiersprache "C". Das ist gut zu wissen, falls man noch Fragen zu dem einen oder anderen Punkt hat und im Internet nach Hilfen für dieses Problem suchen möchte. Außerdem kann hier nur ein Crashkurs in den Grundlagen geliefert werden. Wer seine Grundkenntnisse vertiefen möchte, sollte auf jeden Fall das Buch über C lesen. Der einzige Unterschied zwischen C und Objective-C besteht darin, dass Objective-C objektorientiertes Programmieren ermöglicht und C nicht. Wer C schon kann, der sollte dieses ganze zweite Kapitel nur schnell überfliegen und dann gleich zum Dritten vorstoßen.

Um uns ganz auf unsere Code-Beispiele konzentrieren zu können, lassen wir unsere bisherigen beiden Beispielprojekte erst einmal ruhen und starten ein neues Programm, und zwar ein ganz spezielles. Dieses Mal brauchen wir keine Unterscheidung zwischen iPhone- und OS X-Programm, da das, was wir hier lernen für beide Systeme gilt. Wir lassen Xcode also wieder ein neues Projekt für uns erstellen. Dieses Mal wählen wir links erst den Eintrag "Command Line Utility" und dann rechts "Foundation Tool" (Das Einzige mit dem Kakaobecher-Symbol). Als Namen wählen wir "ConsoleTest". Wir haben nun ein Konsolen-Projekt erstellt. Konsolenprogramme haben nichts mit Videospielen zu tun, sondern sind Programme, die sich dem Benutzer nicht als ein Fenster präsentieren, sondern nur als reine Textausgabe, ganz wie es in den Anfängen der Computerzeit üblich war. Das Konsolenprogramm findet sich bei Mac OS X in dem Unterordner "Dienstprogramme" des Programmeordners und heißt "Terminal". Wer mehr über den Umgang mit dem Terminal erfahren will, der muss im Internet nach "bash" suchen. Für unsere Arbeit ist dies jedoch erst einmal nicht wichtig. Wenn wir unser neues Projekt jetzt einmal ganz spontan starten, dann werden wir mit dem frustrierenden Eindruck getäuscht, es wäre nichts passiert. Dem ist aber ganz und gar nicht so. ganz oben links im Xcode-Fenster über der Beschriftung "Page" haben wir zwei Buttons. Der linke davon ist eingerastet. Wir wählen den rechten Knopf und kommen damit in die so genannte Debugging-Ansicht von Xcode. Jetzt wählen wir noch in der Apple-Leiste unter "Run" den Eintrag "Console" aus. Uns interessiert jetzt nur der untere Bereich von Xcode. Dort sollte jetzt ungefähr folgendes stehen:


[Session started at 2009-04-22 21:47:44 +0200.]
2009-04-22 21:47:44.370 ConsoleTest[1404:10b] Hello, World!

The Debugger has exited with status 0.


Klicken wir noch einmal auf "Build and Go", dann bekommen wir den Selben Text noch einmal, nur die angezeigte Zeit ist aktueller.
Unser Projekt besitzt weniger Dateien, als unsere letzten beiden, da dieses Projekt viel simpler aufgebaut ist. Tatsächlich ist die einzige Datei, die wir beachten müssen "ConsoleTest.m".
Ihr Inhalt sieht wie folgt aus:

#import <Foundation/Foundation.h>
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    // insert code here...
    NSLog(@"Hello, World!");
    [pool drain];
    return 0;
}

Hier finden wir also das "Hello, World!" wieder... wir ändern diesen Text jetzt einmal in "wooooowhullahupoderso" und testen dann gleich unser Programm (Wenn gefragt wird, ob vorher gespeichert werden soll: Grundsätzlich immer bestätigen). Wir erhalten folgendes:
[Session started at 2009-04-22 23:24:40 +0200.]
2009-04-22 23:24:40.713 ConsoleTest[1578:10b] wooooowhullahupoderso

The Debugger has exited with status 0.

[Bearbeiten] Funktionen

Konzentrieren wir uns zunächst auf die Zeile, an der wir gerade herumgespielt haben:

    NSLog(@"wooooowhullahupoderso");

"NSLog" ist eine so genannte Funktion. Funktionen "machen etwas". Im Falle von NSLog ist dies das Ausgeben von Text in der Konsole. In unserem Beispiel müssen wir der Funktion aber auch etwas geben, damit sie ihren Dienst verrichten kann. In diesem Fall einen so genannten "String". "String" bedeutet nichts weiter als "etwas Text". Damit ein Text ein String wird, muss er in Anführungsstriche gesetzt, und ihm ein @ vorangestellt werden: @"Beispiel". Der Text darf keinesfalls weitere Anführungszeichen enthalten. Wie man diese trotzdem noch anzeigen lassen kann wird später noch erklärt.
Wenn man einer Funktion nun also einen Wert geben will, setzt man diesen hinter den Namen der Funktion und setzt diesen zusätzlich noch in Klammern. Muss man einer Funktion zwei Werte mitgeben, trennt man diese durch ein Komma, man muss aber dabei unbedingt die richtige Reihenfolge beachten. Benötigt die Funktion keine Werte, lässt man den Inhalt der Klammern leer. An das Ende kommt dann immer noch ein Semikolon. Funktionen ruft man also ganz allgemein so auf:

   ichBinEineFunktionA(9);
   ichBinEineFunktionB(@"Hallo", 67);
   ichBinAuchEineFunktion();

Diese Funktionen ergeben natürlich keinen Sinn, denn diese Funktionen gibt es ja gar nicht. Weder hat Apple diese Funktionen veröffentlicht, noch haben wir diese Funktionen schon selbst geschrieben. Es geht hier nur darum zu demonstrieren, wie man Funktionen aufruft.
Man kann Funktionen aber nicht nur aufrufen, man kann sie auch selbst schreiben. Die wichtigste Funktion eines Konsolenprogramms ist:

int main (int argc, const char * argv[]) 
{ 
 
}

Alles was innerhalb der geschweiften Klammern steht, wird ausgeführt, wenn man diese Funktion aufruft. int main ist besonders, weil dies die erste Methode ist, die überhaupt aufgerufen wird. Man ruft int main im Gegensatz zu allen anderen Funktionen auch nicht selbst auf. In den geschweiften Klammern von int main beginnt unser Programm, wir rufen diese Funktion also auf, wenn wir in Xcode auf "build and go" klicken. Wurde sämtlicher Code in dieser Funktion aufgerufen, dann ist das Programm fertig und beendet. Da unser Programm bis jetzt nur eine einzige Zeile Text ausgibt, geschieht dies natürlich sehr schnell. Die main-Funktion sieht jetzt vielleicht noch ein wenig kompliziert aus, deshalb schreiben wir einmal unsere eigene kleine Funktion. Dazu schreiben wir jetzt den Code um, damit er wie folgt aussieht:

#import <Foundation/Foundation.h>
void testeMich();
 
int main (int argc, const char * argv[]) {
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
   // insert code here...
   testeMich();
   testeMich();
   [pool drain];
   return 0;
}
 
void testeMich()
{
   NSLog(@"das funktioniert");
   NSLog(@"das auch");
}

[Session started at 2009-04-26 12:27:41 +0200.]
2009-04-26 12:27:41.679 ConsoleTest[696:10b] das funktioniert
2009-04-26 12:27:41.687 ConsoleTest[696:10b] das auch
2009-04-26 12:27:41.688 ConsoleTest[696:10b] das funktioniert
2009-04-26 12:27:41.688 ConsoleTest[696:10b] das auch

The Debugger has exited with status 0.

Um eine eigene Funktion zu schreiben, muss man zunächst dessen obersten Teil an den Anfang der Code-Datei schreiben und statt den geschweiften Klammern mit dem Inhalt bloß ein Semikolon dahinter stellen. Es hat keinen Sinn sich darüber den Kopf zu zerbrechen, warum man dies machen muss. Manche Programmiersprachen wollen das so, andere nicht. Objective-C will es auf jeden Fall. würden wir diese Zeile weglassen, würde uns der Compiler einen ganzen Haufen Warnungen ausspucken, obwohl der Code trotzdem funktioniert. Nun zu der eigentlichen Definition unserer Funktion. void bedeutet, dass diese Funktion keinen Rückgabewert besitzt. Ein Rückgabewert ist ein Wert, den die Funktion ausspuckt, wenn man sie aufruft. Will man diesen Wert abfangen, muss man ihn in eine Variable speichern (Mehr zu Variablen im nächsten Abschnitt). Nach einem Leerzeichen kommt dann der Name der Funktion. Er muss einzigartig sein, und mit ihm ruft man später dann auch die Funktion auf, wie man in dem Beispiel gut sehen kann. Dahinter die beiden normalen Klammern, in denen nichts steht, bedeuten, dass dieser Funktion kein Wert beim Aufrufen mitgeteilt werden kann. Als nächstes Kommen dann nur noch die geschweiften Klammern. Zwischen sie schreiben wir den Code, der beim Aufrufen der Funktion ausgeführt werden soll. Ausserhalb von Funktionen schreiben wir niemals Code (abgesehen von einigen ganz speziellen Ausnahmen, die später noch besprochen werden), denn woher soll der Compiler denn dann wissen, an welche Stelle des Programms dieser Code gehört?

[Bearbeiten] Variablen

Wir gehen jetzt noch einen Schritt weiter, und lernen, wie wir Funktionen selbst schreiben, die Werte ausgeben oder sich Werte beim Aufruf mitgeben lassen. Wir verändern wieder erst einmal den Code und besprechen die Änderungen dann im Detail.

#import <Foundation/Foundation.h>
int testeMich(int eineNummer);
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
    // insert code here...
    int a;
    int b;
    a = testeMich(1);
    b = testeMich(2);
    NSLog(@"%i + %i = %i", a, b, a+b);
    [pool drain];
    return 0;
}
 
int testeMich(int eineNummer)
{
    NSLog(@"das funktioniert, %i", eineNummer);
    NSLog(@"das auch, %i", eineNummer);
    return eineNummer;
}

[Session started at 2009-04-26 12:28:17 +0200.]
2009-04-26 12:28:17.267 ConsoleTest[708:10b] das funktioniert, 1
2009-04-26 12:28:17.269 ConsoleTest[708:10b] das auch, 1
2009-04-26 12:28:17.270 ConsoleTest[708:10b] das funktioniert, 2
2009-04-26 12:28:17.271 ConsoleTest[708:10b] das auch, 2
2009-04-26 12:28:17.271 ConsoleTest[708:10b] 1 + 2 = 3

The Debugger has exited with status 0.

int beschreibt im Gegensatz zu void tatsächlich einen Wert, und zwar eine Zahl. Es kann irgend eine Zahl sein, die nicht größer als 2147483647, oder kleiner als -2147483648 ist und keine stellen hinter dem Komma besitzt. Diese Einschränkungen gelten aber nicht für jeden Rechner, sondern nur für solche mit 64bit CPU und einem entsprechenden Betriebssystem. Auf einem 32bit-Computer ist dieser Raum enger. int nennt man einen Typ. Wir gehen genauer auf die Bedeutung dieser 'Typen' ein, wenn wir mit der Beschreibung unserer Änderungen fertig sind. Im Moment ist nur wichtig zu wissen: int heißt 'eine Ganzzahl'
Wir haben unsere Funktion zu einem int gemacht, das heißt sie kann uns jetzt eine Zahl geben. In die normalen Klammern hinter dem Namen unserer Funktion haben wir eine Variable geschrieben. Variablen sind dazu da, damit der Computer sich Werte 'merken' kann. Diese Werte (in unserem Fall eine Zahl, da wir ja int benutzen) werden in den Hauptspeicher des Computers geschrieben und bleiben dort höchstens so lange, wie unser Programm geöffnet ist. Im Falle unseres Textprogramms ist das natürlich nur eine sehr kurze Zeit, aber bei Programmen für OS X oder das iPhone sieht das ja schon wieder ganz anders aus. Schauen wir nun den neuen Inhalt von int main an. hier sind 2 interessante neue Zeilen aufgetaucht. int a; und int b; Mit diesen beiden Zeilen sagen wir dem Computer, dass wir gerne 2 neue Variablen hätten. Die eine soll a, und die andere b heißen. Beide sollen die Form einer Zahl haben. Der Computer reserviert uns nun für jede der beiden Variablen einen Platz im Hauptspeicher, der so groß ist, dass jede Zahl zwischen 2147483647 und -2147483648 hinein passt. In den nächsten beiden Zeilen füllen wir nun diese Variablen mit den Werten, die unsere Funktion testeMich ausspuckt (Diese Funktion ist ja jetzt auch int). Unsere Funktion will aber nun selbst erst einmal einen Wert bekommen, deshalb steht in der ersten Zeile eine 1 in Klammern und in der zweiten eine 2. Es hätte aber auch jede andere Zahl zwischen 2147483647 und -2147483648 sein können.
Damit müssen wir nun den Aufbau unserer Funktion betrachten, um zu verstehen, wie der Code weitergeht. Der Kopf der Funktion lautet nun int testeMich(int eineNummer). int am Anfang, weil die Funktion am Ende eine Zahl ausspuckt, teste mich ist immer noch der Name der Funktion und in den Klammern steht nun int eineNummer. int eineNummer heißt genau wie zuvor int a; und int b;, dass im Hauptspeicher Platz für eine Zahl reserviert werden soll. An dieser Stelle gilt für diese Variable jedoch etwas besonderes. Erstens wird diese Variable wieder aus dem Hauptspeicher gelöscht, sobald sämtlicher Code in den geschweiften Klammern der Funktion ausgeführt wurde, zweitens kann man diese Variable nur innerhalb der Funktion benutzen, für den Code innerhalb von int main oder einer anderen Funktion, die wir vielleicht noch schreiben möchten, ist diese Variable also unsichtbar, und drittens bestimmt derjenige, der diese Funktion aufruft, welchen Wert die Variable genau haben soll. Die beiden Aufrufe von NSLog() ignorieren wir einmal kurz und betrachten die Zeile 'return eineNummer;'. Diese lässt den Wert, den der Aufrufende der Funktion mitgegeben hat, auch wieder zurückgeben.
In a steht nun also 1 und in b 2. Den Rest ignorieren wir noch.
Nun wissen wir auch, was das 'return 0;' in der int main zu bedeuten hat. Ändern wir die Zahl zum Beispiel in 1, dann erhalten wir:

The Debugger has exited with status 1.The Debugger has exited with status 1.

Dieser Rückgabewert wird oft verwendet, um bei Konsolenprogrammen dem Benutzer zu zeigen, ob das Programm erfolgreich ausgeführt wurde, oder ob sich Fehler ergeben haben.

statt

    int a;
    int b;

kann man auch einfach

    int a, b;

schreiben. Solange der Typ der Selbe ist, ist diese Schreibweise auch erlaubt. Ausserdem darf man der Variable auch gleich beim Reservieren des Arbeitsspeichers (das nennt man hier auch 'deklarieren') einen Wert geben

    int a = testeMich(1);
    int b = testeMich(2);

oder sogar noch viel kompakter:

    int a = testeMich(1), b = testeMich(2);

Den Namen von Variablen kann man beliebig wählen, allerdings sollte er nur Buchstaben, Zahlen und unterstriche enthalten, keine Leerzeichen besitzen und er muss eindeutig sein, das heißt der Name sollte sich mit keinem Namen einer anderen Funktion, Variable, usw. überschneiden.

Ausser int gibt es noch weitere Typen.

bool kann nur YES oder NO speichern (bool t = YES, r = NO;),
float und double Zahlen mit Kommastellen (statt einem Komma aber immer einen Punkt verwenden!)(float flu = 12.2; double bu = 16.445), wobei double der genauere von beiden Typen ist,
char speichert einen Buchstaben (Beispiel char c = 'b'; oder char c = 'x';) oder eine Zahl zwischen -128 und 127,
long int (ja, mit einem Leerzeichen dazwischen) speichert eine Zahl zwischen -9.223.372.036.854.775.808 und 9.223.372.036.854.775.807 (Dies gilt wieder nur für 64bit) und short int eine Zahl von −32.768 bis 32.767.
Stellt man zusätzlich noch das Wort 'unsigned' vor int, short int, long int, float, double oder char, dann verändert sich ihr Wertebereich so, dass er bei 0 beginnt und sich ausschließlich in den positiven Zahlenbereich erstreckt. Im Falle von unsigned int hätten wir also eine Zahl von 0 bis 4294967295.


Nächstes Kapitel - Zeichenketten und Arrays


Zurück zum Inhaltsverzeichnis

Persönliche Werkzeuge