Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 Hello iPhone
2 Grundlagen
3 Views und Viewcontroller
4 Alles unter Kontrolle
5 Daten, Tabellen und Controller
6 Models, Layer, Animationen
7 Programmieren, aber sicher
8 Datenserialisierung und Internetzugriff
9 Jahrmarkt der Nützlichkeiten
A Sicherer Entwicklungszyklus
Stichwort

Download:
- ZIP, ca. 49,9 MB
Buch bestellen
Ihre Meinung?

Spacer
Apps programmieren für iPhone und iPad von Klaus M. Rodewig, Clemens Wagner
Das umfassende Handbuch
Buch: Apps programmieren für iPhone und iPad

Apps programmieren für iPhone und iPad
Galileo Computing
1000 S., geb., mit DVD
39,90 Euro, ISBN 978-3-8362-1915-0
Pfeil 3 Views und Viewcontroller
Pfeil 3.1 Eigene View-Klassen in Cocoa Touch
Pfeil 3.1.1 Zeichnen in Cocoa Touch
Pfeil 3.1.2 Zeitberechnung
Pfeil 3.1.3 View-Erzeugung über NIB-Dateien
Pfeil 3.1.4 Aktualisierung der Zeitanzeige
Pfeil 3.1.5 Wiederverwendbarkeit von Views
Pfeil 3.2 Views und Viewcontroller
Pfeil 3.2.1 Outlets
Pfeil 3.2.2 Outlet-Collections
Pfeil 3.2.3 Containerviews
Pfeil 3.2.4 Viewhierarchien
Pfeil 3.2.5 Actions
Pfeil 3.2.6 Ereignisse
Pfeil 3.2.7 Controlzustände und Buttons
Pfeil 3.2.8 Direkte Gestenverarbeitung
Pfeil 3.2.9 Übergänge
Pfeil 3.2.10 Der Lebenszyklus eines Viewcontrollers
Pfeil 3.2.11 Speicher- und Ressourcenverwaltung des Viewcontrollers
Pfeil 3.3 Lokale Benachrichtigungen
Pfeil 3.3.1 Benachrichtigungen versenden
Pfeil 3.3.2 Benachrichtigungen verarbeiten
Pfeil 3.4 Eine App für alle
Pfeil 3.4.1 Das Retina-Display
Pfeil 3.4.2 Sprachkursus für die App
Pfeil 3.4.3 Es funktioniert nicht
Pfeil 3.4.4 Launch-Images und iPhone 5
Pfeil 3.4.5 Universelle Apps
Pfeil 3.5 Fehlersuche
Pfeil 3.5.1 Logging
Pfeil 3.5.2 Der Debugger
Pfeil 3.5.3 Die Debuggerkonsole
Pfeil 3.5.4 Laufzeitfehler

Galileo Computing - Zum Seitenanfang

3.5 FehlersucheZur nächsten Überschrift

Beim Programmieren Ihrer ersten App ist wahrscheinlich der eine oder andere Fehler aufgetreten. Dabei haben Sie schon die ersten Möglichkeiten zur Fehlersuche kennengelernt, als Xcode Sie nach der Übersetzung auf Fehler hingewiesen hat. Außerdem hat Xcode Ihnen vielleicht Warnungen angezeigt. Der Issue Navigator (siehe Abbildung 3.50), den Sie über die Tastenkombination cmd + 4 erreichen, zeigt Ihnen alle Fehler mit roten Punkten und Warnungen mit gelben Dreiecken zu Ihrem Code an. Sie können durch Anklicken eines Fehlers oder einer Warnung direkt zu der entsprechenden Programmstelle gelangen.

Abbildung

Abbildung 3.50 Der Issue Navigator

Fehler und Warnungen unterscheiden sich darin, dass sich ein fehlerhafter Code nicht übersetzen oder gar ausführen lässt. Erhalten Sie bei der Übersetzung nur Warnungen, erzeugt Xcode trotzdem ein ausführbares Programm. Allerdings enthält dieses Programm möglicherweise Laufzeitfehler, die es ganz oder teilweise unbrauchbar machen. Sie sollten also Ihren Programmcode immer so formulieren, dass auch keine Warnungen bei der Übersetzung auftreten.

Schlagen Sie die Warnungen nicht einfach in den Wind!

Sie sollten die Warnungen auf keinen Fall ignorieren, sondern den Ursachen dafür auf den Grund gehen und diese beseitigen. Gerade als Anfänger werden Sie dabei viel lernen. Das leichtfertige Ignorieren von Warnungen oder das unbedachte Ändern von Code aufgrund von Warnungen kann fatale Folgen haben.

Wenn Sie den Menüpunkt Analyze unter Product auswählen, untersucht Xcode den Programmcode genauer. Dafür dauert jedoch die Übersetzung des Projekts länger. Xcode verwendet blaue Symbole, um Meldungen des Analyzers darzustellen. Der Analyzer findet eine Reihe von logischen Programmfehlern, die sich erst zur Laufzeit bemerkbar machen. Er kann beispielsweise einige Arten von Speicherlecks oder die Verwendung nicht initialisierter Variablen aufdecken.

Abbildung

Abbildung 3.51 Analyzer-Meldung in Xcode


Galileo Computing - Zum Seitenanfang

3.5.1 LoggingZur nächsten ÜberschriftZur vorigen Überschrift

Eine einfache Möglichkeit der Fehlersuche ist die Verwendung des Loggings. Mit dem Logger können Sie beliebige Texte in die Konsole schreiben. Wenn Sie Ihre App über Xcode ausführen, können Sie die Konsole in einem Teil des Debuggerbereichs sehen. Diesen Bereich können Sie auch über das Menü ViewShow Debug Area oder die Tastenkombination ª + cmd + Y öffnen.

Die Ausgabe Ihrer Apps auf einem Gerät können Sie jedoch auch über Xcode ansehen, indem Sie den Organizer über den Menüpunkt Organizer unter Window öffnen. Dort wählen Sie das Symbol Devices und unter dem gewünschten Gerät den Punkt Console aus.

Über die Funktion NSLog können Sie eine Ausgabe ins Log schreiben. Der Aufruf dieser Funktion ähnelt dem der C-Funktion printf, die Sie vielleicht kennen. NSLog erlaubt Ihnen also formatierte Ausgaben – mit dem Unterschied, dass NSLog einen Objective-C-String als ersten Parameter erwartet, für den Sie möglichst immer ein String-Literal der Form @"..." und keine Variable verwenden sollten. Der LLVM Compiler 4.0 gibt für Variablen im Formatparameter sogar eine Warnung aus.

NSLog mit Format

Sie sollten für den Formatparameter immer ein Literal verwenden, da Variablen Prozentzeichen enthalten können, die zu unerwarteten Ergebnissen oder Abstürzen führen können. Schreiben Sie also lieber NSLog(@"%@", theLogText) statt NSLog(theLogText). Bei der ersten Variante kann der Compiler den Formatparameter überprüfen und Sie bei unpassenden Platzhalter-Wert-Kombinationen (wie beispielsweise für NSLog(@"text = %d", theLogText)) warnen.

Wenn beispielsweise die Variable die Zeichenkette @"Es gibt 10 %einmalig." enthält, erwartet NSLog für den Platzhalter %e einen Fließkommaparameter. Während die erste Variante unproblematisch ist, führt die zweite hingegen zu einem Absturz oder zumindest zu einer ungewöhnlichen Ausgabe.

Hier sind einige Beispiele für Ausgaben mit NSLog:

NSLog(@"Hallo Welt");
NSLog(@"angle=%.2f", theAngle);
NSLog(@"x=%.1f, y=%.1f", thePoint.x, thePoint.y);
NSLog(@"current time=%@", [NSDate date]);
NSLog(@"frame=%@", NSStringFromCGRect(self.frame));

Listing 3.55 Ausgaben mit »NSLog«

Sie sollten beachten, dass Sie Objekte der Klasse NSString nicht über das Format %s, sondern über %@ ausgeben. Das Format %s verwenden Sie für C-Strings, also für Zeiger auf char. Das Format %@ verwenden Sie hingegen für Objekte beliebiger Klassen. Dabei verwendet NSLog für die Ausgabe die Rückgabe der Methode description des Objekts. Diese Methode stellt die Oberklasse NSObject bereit, und Unterklassen können Sie überschreiben.

Mit NSLog können Sie also zur Laufzeit beliebige Texte in die Konsole schreiben. Sie können diese Funktion allerdings auch dazu benutzen, um sich interessante Variablenwerte ausgeben zu lassen; sie ist somit eine einfache Möglichkeit, um die Variablen zur Laufzeit zu überprüfen. Xcode zeigt Ihnen allerdings nicht nur die Log-Ausgaben an, sondern die App speichert sie auch in einer Log-Datei, und Sie können über den Organizer (ª + cmd + 2) unter Devices darauf zugreifen, wenn Sie dort den Punkt Console unter dem Gerätnamen aufrufen.

Achtung, Plaudertaschen

Sie sollten möglichst keine privaten Daten in das Log schreiben, da es sich auch bei fremden Geräten relativ einfach auslesen lässt. Ein Angreifer braucht dazu nur das Gerät an einen Computer anzuschließen und kann dann auf alle Log-Einträge zugreifen. Vermeiden Sie also die Ausgabe von Passwörtern, Konto- oder Kreditkartennummern oder anderen schützenswerten Daten ins Log.


Galileo Computing - Zum Seitenanfang

3.5.2 Der DebuggerZur nächsten ÜberschriftZur vorigen Überschrift

Obwohl Xcode schon recht viele Fehler findet, kann Ihr Programm natürlich trotzdem noch weitere Fehler, sogenannte Laufzeitfehler, enthalten. Wie der Name schon sagt, treten diese Fehler erst bei der Ausführung des Programms auf. Diese Fehler sind leider nicht immer offensichtlich und manchmal nur sehr schwer zu finden. Bei der Verwendung von Threads kann die Fehlersuche sogar zu vorzeitiger Alterung, Haarausfall und schlechtem Atem führen. Mit steigender Programmkomplexität wird das Printf-Debugging über Log-Ausgaben auch zunehmend unbequemer.

Laufzeitfehler lassen sich in der Regel am einfachsten über einen Debugger aufspüren. Damit können Sie Ihr Programm während der Ausführung anhalten, Variablen inspizieren und gegebenenfalls verändern. Sie können das Programm entweder durch einen Pause-Knopf oder durch Haltepunkte (Breakpoints) anhalten und danach die Ausführung schrittweise oder kontinuierlich fortsetzen. Außerdem lassen sich die Breakpoints an Bedingungen knüpfen, was besonders bei Schleifen und wiederholt aufgerufenen Anweisungen hilfreich ist.

Der Debugger gehört dazu

Der Debugger gehört zu den wichtigsten Entwicklungswerkzeugen. Er erleichtert Ihnen nicht nur die Fehlersuche in Ihren Programmen, sondern hilft Ihnen auch, Ihren Code besser zu verstehen. Sie sollten sich also ruhig die Zeit nehmen, sich mit dem Debugger vertraut zu machen.

Das Setzen eines Breakpoints ist einfach. Sie klicken in die graue Leiste links neben Ihrem Quelltext. Es erscheint ein blaugrauer Pfeil, der den Breakpoint symbolisiert (siehe Abbildung 3.52). Der Debugger stoppt dann an dieser Stelle oder an der ersten Anweisung nach dieser Stelle, wenn Sie den Haltepunkt in eine Zeile gesetzt haben, in der keine Anweisung steht. Durch einen Rechtsklick auf das Breakpoints-Symbol und die Auswahl des entsprechenden Menüpunkts können Sie den Breakpoint wieder entfernen. Alternativ verwenden Sie den Breakpoint Navigator CMD-6 dazu oder ziehen den Haltepunkt wieder aus der Leiste. Außerdem erlaubt Xcode Ihnen das Verschieben der Breakpoints in der Leiste.

Abbildung

Abbildung 3.52 Setzen eines Breakpoints

Über den Pop-up-Menüpunkt Edit Breakpoint lässt sich einem Breakpoint auch eine Bedingung zuweisen (siehe Abbildung 3.53). Dabei können Sie in dem Eingabefeld Condition eine beliebige, gültige Bedingung in Objective-C formulieren. Der Debugger hält erst dann an diesem Breakpoint an, wenn die Bedingung erfüllt ist.

Abbildung

Abbildung 3.53 Setzen einer Breakpoint-Bedingung

Wenn der Debugger anhält, zeigt er einen grünen Pfeil links neben dem Quelltext an, der die aktuelle Ausführungsposition darstellt (siehe Abbildung 3.54). Dieser Pfeil heißt auch Programmzeiger. Der Debugger hat allerdings die Anweisung an dieser Position noch nicht ausgeführt.

Abbildung

Abbildung 3.54 Halt des Programms an einem Breakpoint (Zeile 93)

Sie können sich während des Halts die aktuellen Variablenwerte ansehen und sie durch einen Doppelklick auf die betreffende Zeile ändern. Das funktioniert jedoch leider nur bei einfachen Variablen. Bei Zeigern auf Objekte können Sie so lediglich den Zeiger verbiegen (z. B. auf 0 also nil setzen). Außerdem haben Sie über die Steuerungsleiste des Debuggers (siehe Abbildung 3.55) folgende Möglichkeiten:

  • Sie lassen die Ausführung bis zum nächsten Breakpoint oder einem manuellen Halt fortfahren. Während Ihr Programm läuft, zeigt der Debugger statt des Fortfahren- ein Pause-Symbol, mit dem Sie die Ausführung anhalten lassen können.
  • Sie können auch nur die nächste Anweisung ausführen. Durch mehrfaches Anklicken dieses Symbols können Sie Ihr Programm schrittweise ausführen.
  • Falls der Debugger vor einem Methoden- oder Funktionsaufruf angehalten hat, können Sie ihn in diese Methode hineinspringen lassen. Das funktioniert allerdings nur, wenn zu dieser Methode auch die entsprechenden Debugging-Symbole vorhanden sind. Das ist bei den Systembibliotheken in der Regel nicht der Fall. Ansonsten verhält sich diese Funktion wie das schrittweise Ausführen.
  • Analog können Sie auch aus einer Methode hinausspringen. Der Debugger läuft dabei so lange weiter, bis er die aktuelle Methode verlässt. Das funktioniert auch, wenn die Methode aus dem Betriebssystem oder einer Programmbibliothek heraus aufgerufen wurde. Sie bekommen dann statt Objective-C-Quellcode Assembler-Anweisungen zu sehen.
  • Die Steuerungsleiste zeigt Ihnen den aktuellen Thread an, in dem sich das Programm gerade befindet. Über eine Liste können Sie auch die anderen Threads auswählen und ansehen.
  • Außerdem zeigt die Steuerleiste Ihnen die oberste Methode beziehungsweise Funktion des Stapels des ausgewählten Threads an. Durch Anklicken können Sie sich die anderen Methoden und Funktionen auf dem Stapel ansehen und in diese wechseln.

    Abbildung

    Abbildung 3.55 Steuerungsleiste des Debuggers

Die Funktionsweise des Debuggers soll jetzt anhand des Beispielprojekts verdeutlicht werden. Setzen Sie dazu einen Breakpoint in die erste Zeile der Actionmethode updateViews in der Klasse AlarmClockViewController, und starten Sie die App über Xcode. Der Simulator öffnet das Programm, und der Debugger stoppt die Ausführung in der ersten Zeile dieser Methode.

Die Variablenansicht, die sich unter der Steuerleiste des Debuggers befindet, zeigt unter anderem auch das Symbol self mit einem Dreieck zum Aufklappen an. In diesem Symbol finden Sie die Attribute des Viewcontrollers und eine Zeile mit dem Namen UIViewController. Diese Zeile repräsentiert die Daten der Oberklasse des Objekts. Sie können die Attribute und das Symbol für die Oberklasse aufklappen und sich auch dort die enthaltenen Attribute ansehen.

Klicken Sie jetzt das auf Symbol, um die nächste Anweisung auszuführen. Der grüne Pfeil springt zur nächsten Zeile. Danach klicken Sie mehrmals auf das Symbol, bis der Programmzeiger in der letzten Zeile der Methode mit der Anweisung [self updateTimeLabel]; steht. Bei der schrittweisen Ausführung des Codes ist Ihnen sicherlich aufgefallen, dass der Debugger nur einen Block der Bedingung durchlaufen hat. Welchen Block die App durchläuft, hängt natürlich vom Benachrichtigungsobjekt in der Methode ab.

Springen Sie mit dem Debugger jetzt in die Methode updateTimeLabel, indem Sie auf das Symbol zum Hineinspringen in eine Methode klicken. Der Debugger hält in der ersten Zeile der Methode updateTimeLabel. Wenn Sie das Symbol zum Verlassen der Methode anklicken, springt der grüne Pfeil in die Zeile mit der letzten schließenden, geschweiften Klammer der Methode updateViews.

Löschen Sie den Breakpoint über das Popupmenü, und setzen Sie danach einen Breakpoint in die letzte Zeile der Methode angleWithPoint: der Klasse ClockControl. Geben Sie über den Pop-up-Menüpunkt Edit Breakpoint die Bedingung theAngle < 0 ein, und führen Sie danach das Programm aus. Der Debugger sollte jetzt nur anhalten, wenn Sie den Alarmzeiger in die linke Hälfte der Uhr bewegen. Denn dann ist der Winkel, den die Funktion atan2 liefert, kleiner als 0.


Galileo Computing - Zum Seitenanfang

3.5.3 Die DebuggerkonsoleZur nächsten ÜberschriftZur vorigen Überschrift

Der Debugger in Xcode basiert auf dem Kommandozeilenprogramm gdb oder dem moderneren lldb, den Xcode ab Version 4.3 als Standarddebugger verwendet. Sie können den Debugger über das Schema (siehe Kapitel 8) explizit auswählen. Die nachfolgend aufgeführten Befehle beziehen sich alle auf den lldb.

Xcode wandelt Ihre Eingaben (z. B. zum Setzen eines Breakpoints mit der Maus) in Debuggerbefehle um. Diese grafische Steuerung des Debuggers ist zwar sehr praktisch, allerdings nicht immer ausreichend. Über die Debuggeransicht haben Sie auch Zugriff auf die Debuggerkonsole (siehe Abbildung 3.56), die Sie auch über ª + cmd + C öffnen können. Mit den drei Buttons über der Ansicht können Sie einstellen, ob Sie nur die Variablenansicht, die Debuggerkonsole oder beide Ansichten sehen möchten. In der Debuggerkonsole finden Sie alle Log-Ausgaben Ihrer App und auch alle Ausgaben des Debuggers. Außerdem können Sie hinter dem Prompt (lldb) Befehle für den Debugger eingeben.

Befehlseingabe

Sie können in die Debuggerkonsole nur dann Befehle eingeben, wenn Sie die Ausführung Ihres Programms durch einen Breakpoint oder die Pausetaste angehalten haben. Die Konsole zeigt auch nur dann eine Eingabeaufforderung (Prompt) an. Jeden Befehl schließen Sie durch einen Zeilenvorschub (Return oder Enter) ab, damit der Debugger den Befehl auch ausführt.

Der lldb besitzt einen sehr großen Befehlsumfang, deren vollständige Beschreibung den Rahmen dieses Buches sprengen würde, weswegen dieser Abschnitt nur die wichtigsten Befehle behandelt. Sie können jedoch sehr viele Befehle über die GUI-Einbindung in Xcode ausführen, und viele Befehle brauchen Sie auch eher selten. Glücklicherweise besitzt der Debugger zudem noch eine eingebaute Hilfe, mit der Sie schnell jeden beliebigen Befehl nachschlagen können. Sie rufen die Hilfe über das Kommando help auf, worauf lldb mit den vorhandenen Hilfekategorien antwortet.

In der Kürze liegt die Würze

Sie dürfen Debuggerkommandos abkürzen, solange der Befehl dabei eindeutig bleibt. Anstatt »help« können Sie also auch »he« oder nur »h« eingeben, und der Debugger zeigt Ihnen auch für diese Eingaben die Hilfe an.

Abbildung

Abbildung 3.56 Die Debuggerkonsole in Aktion

Hinter das Hilfekommando können Sie den Namen einer Kategorie oder eines Kommandos schreiben. Dann zeigt Ihnen der Debugger die Hilfe zu dieser Kategorie beziehungsweise zu diesem Kommando an. Wenn Sie beispielsweise »help help« eingeben, sehen Sie den Hilfetext zum Kommando help.

Ablaufsteuerung

Über die Debuggerkonsole steuern Sie die Ausführung Ihrer App. Nach dem Halt an einem Breakpoint können Sie das Programm über den Befehl continue oder c weiterlaufen lassen. Dieses Kommando akzeptiert eine Zahl als optionales Argument. Die Zahl gibt an, wie oft der Debugger diesen Breakpoint erreichen muss, damit er wieder daran anhält. Wenn Sie also »c 4« eingeben, dann ignoriert der Debugger dreimal diesen Breakpoint und stoppt erst beim vierten Mal.

Über das Kommando step oder kurz s weisen Sie den Debugger an, die aktuelle Anweisung auszuführen. Falls das ein Funktions- oder Methodenaufruf ist, springt der Debugger da hinein. Auch diesem Kommando können Sie über ein optionales Argument mitteilen, wie oft der Debugger es ausführen soll. Beispielsweise führt der Debugger mit dem Kommando s 4 die vier nächsten Anweisungen aus.

Analog zu step funktioniert das Kommando next oder n, außer dass es keine Subroutinen anspringt. Mit next können Sie also Methoden- oder Funktionsaufrufe einfach überspringen. Auch bei diesem Befehl können Sie wieder durch ein optionales Argument angeben, wie oft der Debugger es ausführen soll.

Die aktuelle Funktion oder Methode können Sie über den Befehl finish oder fin verlassen. Der Debugger lässt dann das Programm so lange weiterlaufen, bis es die aktuelle Methode oder Funktion beendet hat. Wenn Sie den Debugger beispielsweise an einem Breakpoint in der Klasse drawClockHands anhalten lassen und den Befehl fin eingeben, springt der Programmzeiger ans Ende der drawRect:-Methode hinter die Anweisung [self drawClockHands].

Datenausgabe

Die am häufigsten verwendeten Kommandos sind wahrscheinlich print-object und print, die Sie aufgrund ihrer häufigen Verwendung auch mit po und p abkürzen können. Beide Befehle dienen dazu, Programmdaten auszugeben, wobei Sie hinter den Befehl einen Objective-C-Ausdruck schreiben müssen.

Mit print-object können Sie ein Objective-C-Objekt ausgeben. Wenn Sie beispielsweise einen Breakpoint in die Methode viewDidLoad wie in Abbildung 3.56 setzen und nach dem Halt des Programms an dieser Stelle den Befehl po self oder alternativ print-object self eingeben, erhalten Sie ungefähr die Ausgabe <AlarmClockViewController: 0x4b828f0>. Dabei kann die hexadezimale Zahl 0x4b828f0 am Ende abweichen, weil sie die Speicheradresse des Objekts angibt, die sich bei jedem Programmlauf ändern kann. Sie können auch kompliziertere Ausdrücke verwenden und sich beispielsweise mit po [[self textLabel] text] den Wert des Labels für die Anzeige der Alarmzeit ausgeben lassen. Leider dürfen Sie hier aber nicht die Punktnotation verwenden, weil der Debugger sie nicht kennt. Der Befehl po self.textLabel.text führt zur Ausgabe There is no member named textLabel.

Für die Textausgabe eines Objekts in der Konsole muss der Debugger das Objekt in eine Zeichenkette umwandeln, sofern es nicht bereits eine ist. Dazu verwendet er die Methode description des Objekts. Sie können diese Methode also überschreiben, um die Ausgabe im Debugger anzupassen. Für die Klasse AlarmClockViewController können Sie die Methode aus Listing 3.56 verwenden. Dann gibt Ihnen der Debugger die eingestellte Alarmzeit und den Zustand des Alarmschalters aus.

- (NSString *)description {
return [NSString stringWithFormat:@"alarm: %@ (%d)", Zeilenumbruch
self.timeLabel.text, self.alarmSwitch.on];
}

Listing 3.56 Anpassung der Debuggerausgabe

Über den Befehl print können Sie einfache und zusammengesetzte Datentypen ausgeben. Allerdings müssen Sie hierbei dem Debugger unter Umständen mitteilen, welchen Typ die Ausgabe hat. Um das an einem praktischen Beispiel zu sehen, setzen Sie einen Breakpoint in die Zeile mit der vierten Anweisung [Diese Anweisung lautet: CGContextSaveGState(theContext);] in der Methode drawRect: der Klasse ClockView und starten die Ausführung. Wenn die Ausführung in dieser Zeile hält, können Sie sich den Wert der Variablen theRadius über das Kommando p theRadius anzeigen lassen. Vor dem Wert steht ein Dollarzeichen, gefolgt von einer fortlaufenden Nummer und einem Gleichheitszeichen, also beispielsweise: $1 = 160. [Die Nummer hinter dem Dollarzeichen hängt davon ab, wie oft Sie bereits den print-Befehl aufgerufen haben. Es ist also nicht schlimm, wenn in Ihrer Konsole eine andere Nummer steht.] Der Debugger merkt sich die ausgegebenen Werte in internen Variablen, die Sie sich jederzeit über print wieder ausgeben lassen können (z. B. mit p $1). Sie können diese Variablen sogar in Ausdrücken verwenden und damit rechnen (z. B. p 2 * $1 + 20).

Wert versus Ausdruck

Die Debuggervariablen speichern immer den Wert, das heißt das Ergebnis, des Ausdrucks und nicht den Ausdruck. Sie können damit also alte Variablenwerte abfragen. Wenn Sie zu einem späteren Zeitpunkt wieder p $1 eingeben, erhalten Sie immer den Variablenwert 160 – unabhängig davon, welchen Wert die Variable theRadius momentan hat.

Das klappt auch mit der Struktur theBounds und dem Befehl p theBounds. Die Ausgabe sieht auf einem iPhone so aus:

$3 = {
origin = {
x = 0,
y = 0
},
size = {
width = 320,
height = 320
}
}

Der Debugger gibt Ihnen also schön die Werte in der Struktur aus. Wenn Sie sich den Frame des Views ausgeben lassen wollen und p [self frame] eingeben, liefert Ihnen der Debugger hingegen die Fehlermeldung:

Unable to call function "objc_msgSend" at 0x14c908c: no return type information available.
To call this function anyway, you can cast the return type explicitly (e.g. 'print (float) fabs (3.0)')

Das liegt daran, dass der Debugger nicht den Rückgabetyp der Methode frame ermitteln kann. Sie können ihm jedoch mit einem Typcast auf die Sprünge helfen. Wenn Sie p (CGRect)[self frame] eingeben, erhalten Sie die gewünschte Ausgabe.

print-object oder print?

Sie sollten den print-object-Befehl nur aufrufen, wenn Sie sicher sind, dass der Ausdruck auch wirklich eine Referenz auf ein Objekt liefert. Bei einfachen Datentypen, wie beispielsweise po theRadius oder po theBounds, führt dieser Befehl zum Absturz Ihrer App. Sie müssen sie dann erst wieder neu starten, um sie weiter entwanzen zu können. Der Aufruf des print-Befehls auf eine Objektreferenz ist hingegen harmlos und wenig informativ. Sie erhalten als Ausgabe im Falle eines Zeigers auf ein Objective-C-Objekt den Zeigertyp und die Speicheradresse.

Automatische Ausgaben

Beim Debuggen tritt häufig der Fall auf, dass das Programm an einem bestimmten Breakpoint mehrmals hält und Sie sich den Wert bestimmter Variablen ansehen wollen. Beispielsweise könnten Sie jedes Mal, wenn die Ausführung in drawRect: stoppt, den Wert der Variablen theRadius sehen wollen. Natürlich können Sie nach jedem Halt p theRadius aufrufen, was allerdings auf die Dauer sehr unbequem ist. Stattdessen können Sie auch den Befehl display mit einem Ausdruck als Argument verwenden. Wenn Sie den Befehl display theRadius eingeben, antwortet Ihnen der Debugger mit 1: theRadius = 160. Jedes Mal, wenn er diesen Breakpoint erreicht, gibt er Ihnen den Wert der Variablen theRadius aus. Sie können auch mehrere automatische Ausgaben an einem Breakpoint machen. Dazu brauchen Sie nur entsprechend weitere display-Befehle absetzen. Wenn Sie mit dem Befehl display theBounds eine weitere automatische Ausgabe anlegen, gibt Ihnen der Debugger bei jedem Halt an diesem Breakpoint die Werte dieser beiden Variablen aus.

Keine automatische Ausgabe von Objekten

Es gibt leider keinen analogen Befehl zu print-object für display. Sie können sich jedoch eine Behelfslösung basteln. Der Befehl print-object ruft ja die description-Methode des Objekts auf, um das Objekt in eine Zeichenkette der Klasse NSString umzuwandeln. Die Klasse NSString hat die Methode cString, die den Inhalt der Zeichenkette char-Array liefert. Arrays vom Typ char kann der Debugger über die Befehle print oder display anzeigen; Sie können das ausnutzen, um beliebige Objekte in einer automatischen Ausgabe anzuzeigen, wie z. B. display (char *)[[self description] cString]. Anstelle von self können Sie natürlich auch jede beliebige andere Objektreferenz verwenden.

Über den Befehl target stop-hook list erhalten Sie eine Liste aller automatischen Ausgaben. Nach den zwei display-Kommandos sollten Sie also die folgende Ausgabe sehen:

Hook: 1
State: enabled
Commands:
expr -- theBounds

Hook: 2
State: enabled
Commands:
expr -- theRadius

Die erste Zeile jedes Hooks enthält die Nummer der Ausgabe und die dritte den Ausdruck, den Sie im display-Befehl angegeben haben. In der zweiten Zeile können Sie sehen, ob die Ausgabe aktiv (enabled) oder inaktiv (disabled) ist.

Über den Befehl undisplay lässt sich die automatische Ausgabe eines Ausdrucks stoppen. Wenn Sie nur eine Ausgabe löschen wollen, müssen Sie die Zahl, die am Anfang der Ausgabe steht, als Argument angeben. Sie können also die Ausgabe von theResult durch den Befehl undisplay 1 wieder unterdrücken.

Wenn Sie die Ausgabe eines Ausdrucks nur temporär unterdrücken möchten, können Sie ihn über den Befehl target stop-hook disable und die Angabe der Nummer deaktivieren. Mit dem Befehl target stop-hook disable 2 deaktivieren Sie beispielsweise die Ausgabe der Variablen theBounds. Analog erlaubt Ihnen der Befehlteil enable, eine deaktivierte Ausgabe wieder zu aktivieren. Das heißt, mit target stop-hook enable 2 schalten Sie die automatische Ausgabe dieser Variablen wieder ein.

Werte verändern

Der Debugger erlaubt jedoch nicht nur die Anzeige, sondern auch die Veränderung von Variablenwerten. Sie können damit beispielsweise ausprobieren, wie sich Ihr Code mit anderen Werten verhält. Um einen Wert in der Debuggerkonsole zu setzen, verwenden Sie den Befehl expression mit einer gewöhnlichen Zuweisung in Objective-C-Syntax. Zum Beispiel können Sie über expression theRadius = 200 den Wert der Variablen theRadius in der Methode drawRect: verändern. Das geht auch mit den Attributen in einer Struktur, wie beispielsweise expression theBounds.position.x = 10.


Galileo Computing - Zum Seitenanfang

3.5.4 LaufzeitfehlerZur vorigen Überschrift

Viele Laufzeitfehler enden in einem Absturz des Programms. In einigen Fällen bekommen Sie einen Hinweis auf die Ursache. Der Debugger zeigt Ihnen die Stelle, die den Absturz ausgelöst hat, und in bestimmten Fällen finden Sie in der Konsole eine Fehlermeldung. Die Absturzstelle entspricht allerdings in vielen Fällen nicht der Absturzursache, und diese Stelle ist häufig auch in Systembibliotheken zu finden.

Das bedeutet jedoch nicht, dass Sie einen Bug in iOS gefunden haben. Cocoa Touch wird jeden Tag von vielen Millionen Entwicklern wie Ihnen getestet, und Sie sollten zuerst immer davon ausgehen, dass Ihr Code den Fehler verursacht hat. Natürlich ist auch iOS nicht fehlerfrei. Einen Bug in den Systembibliotheken kann hingegen nur Apple beheben, und Sie sollten vorher alle Möglichkeiten ausprobieren, um Ihre App zum Laufen zu bekommen.

Nach einem Absturz wird die Absturzstelle mit dem Absturzsignal im Quellcode angezeigt. Dieses Signal gibt häufig direkt oder indirekt einen Hinweis auf die Absturzursache.

Abbildung

Abbildung 3.57 Anzeige der Absturzstelle mit dem Signal (SIGABRT)

Der Absturz in Abbildung 3.57 hat das Signal SIGABRT ausgelöst. Das geschieht in der Regel, wenn das Programm eine Ausnahme ausgelöst hat. Die finden Sie in der Konsole des Debuggers. Dabei erfolgt die Ausgabe der Ausnahme in fetter Schrift und ist in zwei Teile unterteilt. Die erste, sehr lange Zeile enthält eine Beschreibung der Ausnahme, und die restlichen Zeilen enthalten den Stacktrace. Das ist die Aufrufliste der Methoden des Programms bis zur Fehlerstelle.

Die Beschreibung der Ausnahme in Abbildung 3.57 lautet:

Terminating app due to uncaught exception 'NSUnknownKeyException',Zeilenumbruch
reason: '[<UIViewController 0x4b44d90> setValue:forUndefinedKey:]:Zeilenumbruch
this class is not key value coding-compliant for the key clockControl.'

Ihr Programm hat also versucht, bei einem Objekt zum Schlüssel clockControl einen Wert zu setzen. Die Meldung gibt auch die Klasse des Objekts (UIViewController) aus, und das ist der Hinweis auf die Ursache. In der Regel verwenden Sie Unterklassen von UIViewController und erzeugen keine Objekte dieser Klasse. Dieser Fehler tritt häufig auf, wenn eine XIB-Datei einen Viewcontroller anlegt, der Entwickler indes vergessen hat, diesem Objekt über dessen Identitätsinspektor die richtige Klasse zuzuweisen. Der erste Schritt zur Behebung dieses Fehlers ist also die Überprüfung der Klasse des entsprechenden Viewcontroller-Objekts in der XIB-Datei.

Abbildung

Abbildung 3.58 Ausgabe nach Programmabsturz durch eine Ausnahme

Ein anderes Signal, das Sie wahrscheinlich relativ häufig zu sehen bekommen, ist EXC_BAD_ACCESS. Dieses Signal bedeutet, dass die App auf eine unerlaubte Speicherstelle zugreifen wollte, und deutet in der Regel auf einen Dangling Pointer hin.

Hier sollten Sie zunächst über den Analyzer versuchen, den Fehler einzukreisen. Für das Aufspüren von Fehlern bei der Speicherverwaltung können Sie auch das Programm Instruments verwenden, das Kapitel 6, »Models, Layer, Animationen«, vorstellt.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.







<< zurück
  Zum Katalog
Zum Katalog: Apps programmieren für iPhone und iPad

Apps programmieren für iPhone und iPad
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Einstieg in Objective-C 2.0 und Cocoa





 Einstieg in
 Objective-C 2.0
 und Cocoa


Zum Katalog: Apps entwickeln für iPhone und iPad - Videotraining






 Apps entwickeln für
 iPhone und iPad -
 Videotraining


Zum Katalog: Apps mit HTML5 und CSS3






 Apps mit HTML5
 und CSS3


Zum Katalog: iPhone- und iPad-Apps entwickeln






 iPhone- und
 iPad-Apps entwickeln


Zum Katalog: Android 4






 Android 4


Zum Katalog: Android-Apps entwickeln - Videotraining






 Android-Apps
 entwickeln -
 Videotraining


Zum Katalog: Windows Store Apps mit XAML und C#






 Windows Store Apps
 mit XAML und C#


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de