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

Inhaltsverzeichnis
Geleitwort
Vorwort
1 Hello iPhone
2 Die Reise nach iOS
3 Sehen und anfassen
4 Alles unter Kontrolle
5 Daten, Tabellen und Controller
6 Models, Layer, Animationen
7 Programmieren, aber sicher
8 Datenserialisierung und Internetzugriff
9 Multimedia
10 Jahrmarkt der Nützlichkeiten
Stichwort

Jetzt 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
Rheinwerk Computing
1172 S., geb., mit DVD
49,90 Euro, ISBN 978-3-8362-2734-6
Pfeil 3 Sehen und anfassen
Pfeil 3.1 Eigene Viewklassen in Cocoa Touch
Pfeil 3.1.1 Zeichnen in Cocoa Touch
Pfeil 3.1.2 Zeitberechnung
Pfeil 3.1.3 View-Erzeugung über Storyboards
Pfeil 3.1.4 Aktualisierung der Zeitanzeige
Pfeil 3.1.5 Wiederverwendbarkeit von Views
Pfeil 3.1.6 Zeichenfarbe festlegen
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 View-Hierarchien
Pfeil 3.2.5 Actions
Pfeil 3.2.6 Ereignisse
Pfeil 3.2.7 Controlzustände und Buttons
Pfeil 3.2.8 Touch-A, Touch-A, Touch Me
Pfeil 3.2.9 Übergänge
Pfeil 3.2.10 Ein kleines Intermezzo über Labels
Pfeil 3.2.11 Beliebige Objekte im Storyboard
Pfeil 3.2.12 Der Lebenszyklus eines Viewcontrollers
Pfeil 3.2.13 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 Launch-Images
Pfeil 3.4.3 Sprachkursus für die App
Pfeil 3.4.4 Es funktioniert nicht
Pfeil 3.4.5 Unterstützung älterer iOS-Versionen
Pfeil 3.4.6 Base-Internationalisierung ausschalten
Pfeil 3.4.7 Universelle Apps
Pfeil 3.5 Geräteausrichtungen, Autosizing und Autolayout
Pfeil 3.5.1 Flexible Views dank Autosizing
Pfeil 3.5.2 Autolayout
Pfeil 3.5.3 Restriktionen im Interface-Builder festlegen
Pfeil 3.5.4 Autolayout und Lokalisierung
Pfeil 3.6 Fehlersuche
Pfeil 3.6.1 Logging
Pfeil 3.6.2 Der Debugger
Pfeil 3.6.3 Breakpoints verwalten
Pfeil 3.6.4 Die Debugger-Konsole

Rheinwerk Computing - Zum Seitenanfang

3.6FehlersucheZur 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 vor oder nach der Übersetzung auf Fehler hingewiesen hat. Außerdem hat Xcode Ihnen vielleicht Warnungen angezeigt. Der Issue-Navigator (siehe Abbildung 3.85), 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 gelangen durch Anklicken eines Fehlers oder einer Warnung direkt zu der entsprechenden Programmstelle.

Abbildung

Abbildung 3.85 Der Issue-Navigator

Dabei unterscheiden sich Fehler und Warnungen 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 produziert 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 ProductAnalyze auswählen, untersucht Xcode den Programmcode genauer. Der Analyzer findet eine Reihe von logischen Programmfehlern, die sich unter Umständen auch erst zur Laufzeit bemerkbar machen, und stellt die Fundstellen über blaue Symbole in Xcode dar. Er kann beispielsweise einige Arten von Speicherlecks oder die Verwendung nicht initialisierter Variablen aufdecken. Zwar hat Apple mit der Einführung des Automatic Reference Countings die Gefahr von Speicherlecks erheblich gemindert; der Analyzer entdeckt jedoch auch Speicherverwaltungsfehler bei der Verwendung der C-Bibliotheken von Apple (z. B. Core Foundation). In Abbildung 3.86 sehen Sie eine typische Analyzer-Meldung für einen solchen Fehler.

Abbildung

Abbildung 3.86 Analyzer-Meldung in Xcode


Rheinwerk Computing - Zum Seitenanfang

3.6.1LoggingZur nächsten ÜberschriftZur vorigen Überschrift

Eine weitere 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, sehen Sie die Konsole in einem Teil des Debugger-Bereichs. Diesen Bereich können Sie auch über das Menü ViewDebug AreaShow Debug Area oder die Tastenkombination ª+cmd+Y öffnen.

Wenn Sie die App auf einem Gerät nicht über Xcode gestartet haben, lässt sich ihre Ausgabe trotzdem über Xcode ansehen, indem Sie den Organizer über den Menüpunkt WindowOrganizer öffnen. Dort wählen Sie den Reiter 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.73 Ausgaben mit »NSLog«

Sie sollten darauf achten, 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 %@ benutzen 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, die Unterklassen überschreiben dürfen.

Mit NSLog können Sie also zur Laufzeit beliebige Texte in die Konsole schreiben. Sie können diese Funktion allerdings auch dazu benutzen, sich interessante Variablenwerte ausgeben zu lassen; sie ist somit eine einfache Möglichkeit, 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 sie über den Organizer, wie oben beschrieben, ansehen.

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.


Rheinwerk Computing - Zum Seitenanfang

3.6.2Der 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, 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 anderen 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: Klicken Sie in die graue Leiste links neben Ihrem Quelltext. Es erscheint ein blaugrauer Pfeil, der den Breakpoint symbolisiert (siehe Abbildung 3.87). 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.87 Setzen eines Breakpoints

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.88). Der Debugger hat allerdings die Anweisung an dieser Position noch nicht ausgeführt.

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 Variablen mit einfachen Datentypen (wie z. B. int, double). Bei Zeigern auf Objekte können Sie so lediglich den Zeiger verbiegen (z. B. auf 0 also nil setzen).

Abbildung

Abbildung 3.88 Halt des Programms an einem Breakpoint

Außerdem haben Sie über die Steuerungsleiste des Debuggers (siehe Abbildung 3.89, von links nach rechts) folgende Möglichkeiten:

  • Blenden Sie den Debugger-Bereich ein oder aus.
  • Deaktivieren und Aktivieren Sie alle Breakpoints auf einmal. Xcode stellt deaktivierte Breakpoints in einem helleren Blauton als aktivierte dar.
  • 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 können.
  • Führen Sie nur die nächste Anweisung aus. Durch mehrfaches Anklicken dieses Symbols können Sie Ihr Programm schrittweise ausführen.
  • Falls der Debugger vor einem Methodenaufruf angehalten hat, können Sie ihn dort hineinspringen lassen. Das funktioniert allerdings nur, wenn dazu 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 herausspringen. Der Debugger läuft dabei so lange weiter, bis er die aktuelle Methode verlässt. Das funktioniert auch, wenn das Betriebssystem oder eine Programmbibliothek diese Methode aufgerufen hat. 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.89 Steuerungsleiste des Debuggers

Die Funktionsweise des Debuggers werden wir jetzt anhand des Beispielprojekts verdeutlichen. Setzen Sie dazu einen Breakpoint in die erste Zeile der Action-Methode 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 das Symbol self mit einem Dreieck zum Aufklappen an. Wenn Sie es aufklappen, finden Sie die Attribute des Viewcontrollers und eine Zeile mit dem Namen UIViewController. Unter dieser Zeile befinden sich 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.

Wenn Sie den Debug-Navigator über cmd+6 öffnen, können Sie sich die Aufrufstapel der einzelnen Threads des Programms ansehen (siehe Abbildung 3.90). Das Programm hat die Methode updateViews im Hauptthread aufgerufen, was Sie am untersten Symbol – der Funktion main – sehen. Der Aufrufer der Methode ist die Methode viewWillAppear:. Wenn Sie die Methode anklicken, springt Xcode in der Methode viewWillAppear: an die Stelle des Aufrufs, also die letzte Zeile (siehe Listing 3.60). Außerdem zeigt Xcode in der Variablenansicht die Variablen der Methode viewWillAppear: an; das ist zum einen self und zum anderen der Parameter inAnimated.

Nebenjobs

Eine iOS-App kann mehrere Arbeitsschritte parallel ausführen; beispielsweise eine Datei aus dem Internet laden und eine Animation anzeigen, die diesen Download für den Nutzer visualisiert. Dabei laufen die parallelen Anweisungen in unterschiedlichen Threads ab. Der Hauptthread – oder auch Main-Thread – des Programms ist dabei der Thread, der die Startfunktion main des Programms ausführt. Wenn dieser Thread endet, endet in der Regel das komplette Programm.

Abbildung

Abbildung 3.90 Der Debug-Navigator von Xcode

Klicken Sie jetzt in der Steuerungsleiste des Debuggers auf das Symbol, um die nächste Anweisung auszuführen. Der grüne Pfeil springt zur nächsten Zeile, und in der Variablenansicht ändert sich der Wert der Variablen theApplication. 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.

Das Berühren der Figüren mit den Pfoten ist ver... äh erlaubt

Mit dem Debugger können Sie sehr viel über Ihr Programm lernen: Wie ändern sich die Variablen, welche Methode wird wann von welcher anderen Methode aufgerufen und vieles mehr. Mit ihm finden Sie Fehler in der Regel viel schneller als mit Code-Analysen oder Log-Ausgaben, und Sie schätzen ihn umso mehr, je mehr Sie ihn benutzen. Sie können mit dem Debugger eigentlich nur einen Fehler machen: ihn nicht zu verwenden.


Rheinwerk Computing - Zum Seitenanfang

3.6.3Breakpoints verwaltenZur nächsten ÜberschriftZur vorigen Überschrift

Sie können nicht nur alle Breakpoints auf einmal deaktivieren oder aktivieren, sondern auch einzeln. Dazu klicken Sie den Breakpoint in der Leiste einmal an, so dass Xcode ihn in einem helleren Blau darstellt. Durch erneutes Anklicken aktivieren Sie ihn wieder.

Das erreichen Sie auch durch Anklicken der Breakpoint-Symbole im Breakpoint-Navigator (siehe Abbildung 3.91), über den Sie auch Exception-Breakpoints setzen können. Der Debugger löst einen Exception-Breakpoint immer dann aus, wenn die App eine Ausnahme wirft. Objective-C verfügt zwar über einen ähnlichen Ausnahme-Mechanismus wie andere Programmiersprachen (z. B. C++ oder Java), allerdings hat sich hier die Ausnahmebehandlung bei weitem nicht so stark durchgesetzt.

Ausnahmen

Über eine Ausnahme (Exception) kann eine Methode ihren Aufrufern einen Fehlerzustand anzeigen, den sie nicht über ihren Rückgabewert ausdrücken kann. Diese Situation tritt beispielsweise ein, wenn das Programm eine Nachricht an ein Objekt sendet, für die es keine entsprechende Methode besitzt. Das ist beispielsweise das der Fall, wenn Sie an das Application-Delegate des Beispielprojekts die Nachricht intValue senden. Die Anweisungen

id theDelegate = [[UIApplication sharedApplication] delegate];
NSLog(@"intValue: %d", [theDelegate intValue]);

sind syntaktisch korrekt, und der Compiler hat hieran auch nichts auszusetzen. Allerdings führen diese Anweisungen zu einem Laufzeitfehler. Die Objective-C-Runtime wirft dabei eine Ausnahme über die Anweisung

@throw [NSException exceptionWithName:...];

Die aufrufenden Methoden können die Ausnahme entweder fangen und verarbeiten, oder das Programm stürzt ab. Wie bereits gesagt, ist die Behandlung von Ausnahmen unter Cocoa Touch eher selten, weswegen wir hier nicht näher darauf eingehen. Falls Sie sich dennoch damit ausführlicher beschäftigen wollen, empfiehlt sich die Lektüre des Dokuments »Introduction to Exception Programming Topics for Cocoa« (http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html).

Exception-Breakpoints aktivieren Sie im Breakpoint-Navigator über den Plus-Button am unteren Rand und die Auswahl des Punktes Add Exception Breakpoint... (siehe Abbildung 3.91).

Abbildung

Abbildung 3.91 Aktivieren des Exception-Breakpoints

Um den Breakpoint zu testen, fügen Sie die beiden Zeilen

id theDelegate = [[UIApplication sharedApplication] delegate];
NSLog(@"intValue: %d", [theDelegate intValue]);

in die Methode viewWillAppear: der Klasse AlarmClockViewController ein und führen die App aus.

Wenn Sie vorher den Exception-Breakpoint aktiviert haben, stoppt der Debugger in dieser Methode in der Anweisung mit dem NSLog-Aufruf, und in der Variablenansicht können Sie sich die Variablenwerte ansehen. Bei einer realen Ausnahme können Sie damit die Variablenwerte untersuchen, um festzustellen, was die Ausnahme verursacht hat; in der Regel hat der Nachrichtenempfänger nicht die erwartete Klasse.

Als Nächstes deaktivieren Sie den Exception-Breakpoint über den Breakpoint-Navigator und führen das Programm erneut aus. Diesmal stoppt der Debugger in der Funktion main an der Aufrufstelle der Funktion UIApplicationMain in der Datei main.m. An dieser Stelle sehen Sie nicht die Methode und ihre Variablen und können den Programmabsturz deshalb nicht genauer analysieren.


Rheinwerk Computing - Zum Seitenanfang

3.6.4Die Debugger-KonsoleZur nächsten ÜberschriftZur vorigen Überschrift

Der Debugger in Xcode basiert auf dem Kommandozeilenprogramm lldb. Xcode wandelt alle bisher besprochenen Anweisungen an den Debugger (z. B. zum Setzen eines Breakpoints mit der Maus) in die entsprechenden Debuggerbefehle um. Diese grafische Steuerung des Debuggers ist zwar sehr praktisch, allerdings nicht immer ausreichend. Über die Debuggeransicht haben Sie auch Zugriff auf die Debugger-Konsole (siehe Abbildung 3.88, unten rechts), die Sie auch über ª+cmd+C öffnen können. Mit den drei Buttons über der Ansicht stellen Sie ein, ob Sie nur die Variablenansicht, die Debugger-Konsole oder beide Ansichten sehen möchten. In der Debugger-Konsole 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 Debugger-Konsole 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 ¢) ab, damit der Debugger den Befehl auch ausführt.

Der Debugger besitzt einen sehr großen Befehlsumfang, dessen 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 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 Debugger-Kommandos 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.

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 Debugger-Konsole 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 ihn ausführen soll.

Die aktuelle Funktion oder Methode verlassen Sie über den Befehl finish oder fin. 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 beziehungsweise 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.92 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: 0x79935e0>. Dabei kann die hexadezimale Zahl 0x79935e0 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 timeLabel] text] den Wert des Labels für die Anzeige der Alarmzeit ausgeben lassen. Hier dürfen Sie auch die Punktnotation verwenden; der Befehl po self.timeLabel.text führt also zur gleichen Ausgabe.

Abbildung

Abbildung 3.92 Ausgabe von Objekten in der Debugger-Konsole

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.74 verwenden. Dann gibt Ihnen der Debugger die eingestellte Alarmzeit und den Zustand des Alarmschalters aus.

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

Listing 3.74 Anpassung der Debuggerausgabe

Wenn Sie den Alarm einschalten und beim Halt des Debuggers in der Methode switchAlarm: den Befehl po self in der Konsole eingeben, erhalten Sie jetzt die Ausgabe alarm: 4:40 (on), wobei natürlich die Alarmzeit von Ihrer Auswahl abhängt.

Die Methode description dient ja auch in anderen Situationen dazu, Objekte in adäquate Zeichenketten umzuwandeln. Wenn Sie im Debugger einen anderen Text ausgeben wollen, als das die Methode description macht, können Sie auch die Methode debugDescription überschreiben, die standardmäßig das Ergebnis des Methodenaufrufs von description zurückgibt.

Die Implementierung von debugDescription in Listing 3.75 gibt zusätzlich zur Methode description die Zeit des Clock-Controls in Sekunden aus.

- (NSString *)debugDescription {
return [NSString stringWithFormat:
@"debug alarm: %@ (%.3fs, %@)",
self.timeLabel.text, self.clockControl.time,
self.alarmHidden ? @"off" : @"on"];
}

Listing 3.75 Zeichenkette für Debug-Ausgabe bereitstellen

Wenn Sie diese Methode in die Klasse AlarmClockViewController einfügen und bei einem Breakpoint das Kommando po self eingeben, antwortet der Debugger mit einer Meldung in der Form debug alarm: 4:40 (16803.488s, on). Das Kommando po [self description] führt hingegen nach wie vor zur Ausgabe von alarm: 4:40 (on).

Ü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, CGContextSaveGState(theContext);, in der Methode drawRect: der Klasse ClockView und starten die Ausführung. Wenn der Debugger in dieser Zeile stoppt, 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: (GGFloat) $0 = 160. [Anm.: 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 $0). Sie können diese Variablen sogar in Ausdrücken verwenden und damit rechnen (z. B. p 2 * $0 + 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 nur 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 mit einem iPhone 5 unter iOS 7 beziehungsweise im entsprechenden Simulator so aus: (CGRect) $0 = origin=(x=0, y=0) size=(width=320, height=320). Auf anderen Gerätetypen weichen unter Umständen die Werte für width und height davon ab. 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, antwortet Ihnen der Debugger hingegen mit der Fehlermeldung:

error: 'frame' has unknown return type;

cast the call to its declared return type

error: 1 errors parsing expression

Das liegt daran, dass der Debugger nicht den Rückgabetyp der Methode frame ermitteln kann. Sie können ihm jedoch mit einem Typecast auf die Sprünge helfen. Wenn Sie p (CGRect)[self frame] eingeben, erhalten Sie die Ausgabe: (CGRect) $1 = origin=(x=0, y=0) size=(width=320, height=320)

»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 zu der Ausgabe [no Objective-C description available]. Der Debugger hat hier erkannt, dass die Variable kein Objekt enthält. Wenn das wie bei po [self frame] nicht möglich ist, führt das zu einem Fehlersignal und der Ausgabe

error: Execution was interrupted, reason:

EXC_BAD_ACCESS (code=1, address=0x65730065).

The process has been returned to the state before

expression evaluation.

Sie können die App danach zwar weiter im Debugger laufen lassen, es kann dabei jedoch zu einem unerwarteten Verhalten der App kommen.

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 Sie das Programm an einem bestimmten Breakpoint halten lassen, um sich den Wert bestimmter Variablen anzusehen. Beispielsweise möchten Sie jedes Mal, wenn die Ausführung in drawRect: stoppt, den Wert der Variablen theRadius sehen. 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 Stop hook #1 added. Jedes Mal, wenn er diesen Breakpoint erreicht, gibt er Ihnen von nun an 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 abzusetzen. 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.

Sie können diese Ausgabe auch ohne Konsole erreichen, indem Sie in dem Kontextmenü des Breakpoints den Punkt Edit Breakpoint... aufrufen und in dem Pop-over-Dialog den Button Add Action anklicken. Für den Punkt Action wählen Sie den Eintrag Debugger Command aus, und in das Eingabefeld geben Sie das Kommando p theRadius wie in Abbildung 3.93 ein. Wenn der Debugger nun an diesem Breakpoint hält, gibt er immer den Wert dieser Variablen automatisch aus. Sie können weitere Befehle hinzufügen, indem Sie auf den Plus-Button klicken. Über die Option Automatically continue after evaluating weisen Sie den Debugger an, dass er nach der Aktion automatisch mit der Ausführung des Programms fortfährt.

Abbildung

Abbildung 3.93 Debugger-Kommando automatisch ausführen

Über den Befehl target stop-hook list erhalten Sie eine Liste aller automatischen Ausgaben, die Sie über den display-Befehl angelegt haben. Nach den zwei display-Kommandos von oben erhalten Sie die folgende Ausgabe:

Hook: 1

State: enabled

Commands:

expr -- theRadius

Hook: 2

State: enabled

Commands:

expr -- theBounds

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 sehen Sie, 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 Debugger-Konsole 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.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück




Copyright © Rheinwerk Verlag GmbH, Bonn 2014
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.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern


  Zum Rheinwerk-Shop
Zum Katalog: Apps programmieren für iPhone und iPad






Neuauflage: Apps programmieren für iPhone und iPad
Jetzt Buch 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: Spieleprogrammierung mit Android Studio






Spieleprogrammierung mit Android Studio


Zum Katalog: Android 5






Android 5


Zum Katalog: iPhone und iPad-Apps entwickeln






iPhone und iPad-Apps entwickeln


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo