Erweitertes Debug

Der Debug-Bereich ist eine nützliche Funktion in der Arbeit von iOS-Entwicklern in Xcode. Sobald wir beginnen, die Entwicklung für iOS zu beherrschen und versuchen, uns von der bekannten und beliebten Druckmethode zu entfernen und schnellere und bequemere Methoden zum Verständnis des Systemzustands in einem bestimmten Zeitraum zu finden, beginnen wir mit dem Studium des Debug-Bereichs.

Höchstwahrscheinlich fallen Ihnen beim Debuggen des Panels die Augen, bevor Sie verstehen, was genau dort passiert. Wenn die Anwendung zum ersten Mal abstürzt, wird das untere Menü automatisch geöffnet. Dies kann zunächst helfen, das Problem zu verstehen (denken Sie an den guten alten "Schwerwiegender Fehler: Index außerhalb des Bereichs"). Grundsätzlich verstehen Sie zu Beginn nicht, was Xcode von uns will, und googeln es Fehler, aber im Laufe des Wachstums werden immer mehr Informationen klar.

Der Programmierer versucht von Anfang an, seine Arbeit zu optimieren. Um dies zu tun, bemühen wir uns zu verstehen, zu welchem ​​Zeitpunkt unser Programm in einen falschen Zustand übergegangen ist. Und hier können die Methoden je nach dem Punkt, an dem sich die Entwicklung des Programmierers befindet, variieren. Zuerst, wie das Debuggen mit der "print ()" - Methode korrekt durchgeführt wird, dann werden Haltepunkte gesetzt und die "po" -Methoden aufgerufen, dann mit der Debug-Variableneingabe (dem Bereich neben der Konsole in Xcode) vertraut gemacht und dann verstanden, wie der Code beim Anhalten kompiliert wird Haltepunktmethoden - „Ausdruck“ (zumindest war das die Entwicklung, die ich hatte).

Probieren wir verschiedene Methoden aus, die uns helfen, den Status unserer Anwendung zu verstehen und zu ändern. Die einfachsten wie "print ()" und "po" werden nicht berücksichtigt. Ich denke, Sie verstehen ihre Essenz bereits und wissen, wie man sie anwendet.

Erstellen wir eine einfache Anwendung mit einem Bildschirm, in dem nur ein Zelltyp (TableViewcell) mit zwei Elementen enthalten ist: UIImageView und UILabel. In die Zellen schreiben wir die Seriennummer und fügen entweder Bild1 oder Bild2 in das Bild ein.

Die tableViewCellForRowAtIndexPath-Methode erstellt Zellen für uns, legt Daten ab und gibt Folgendes zurück:

Bild

Diese Methode generiert die folgende Tabelle:

Bild

Haltepunkt


Lassen Sie uns unser Programm stoppen und unserem Label Text hinzufügen.

1. Haltepunkt setzen:

Bild

2. Das Programm hat die Ausführung in Zeile 55 unmittelbar nach der Zuweisung des Textes gestoppt. Da wir uns auf einer Linie im Sichtfeld der Zelle befinden, können wir mit unserer Zelle interagieren.

3. Wir schreiben in die Konsole einen Befehl, um den Text der Zelle zu ändern:

Bild

4. Wir entfernen unseren Haltepunkt und drücken die Taste "Fortsetzung der Programmausführung".

5. Auf dem Bildschirm unseres Telefons sehen wir, dass alles erfolgreich ausgefallen ist:

Bild

expression führt den Ausdruck aus und gibt einen Wert für den aktuellen Thread zurück.

Haltepunkt bearbeitet


Was aber, wenn wir den Text in einer großen Anzahl von Zellen ändern müssen? Oder haben wir bereits bei der Programmausführung erkannt, dass wir etwas ändern müssen?

Wir können die Ausführung dieser Operation optimieren und die Arbeit etwas beschleunigen, den Text in Zellen ändern, wenn er den Haltepunkt erreicht, und das Programm weiter ausführen. Dies spart viel Zeit und ermöglicht es uns, nicht für jede Zelle dasselbe zu drucken.

Dazu müssen wir unseren Haltepunkt leicht ändern, dort einen zusätzlichen Code hinzufügen, der seinen Text in der Sichtbarkeitszone unserer Zelle ändert, und das Programm fortsetzen.

  1. Haltepunkt erstellen.
  2. Klicken Sie mit der linken Maustaste auf den Haltepunktpfeil.
  3. Klicken Sie auf Haltepunkt bearbeiten.
  4. Bedingung - Bedingungen, unter denen Breakpoint funktioniert, jetzt brauchen wir es nicht mehr.
  5. Ignorieren - wie oft Breakpoint übersprungen werden muss, bevor es funktioniert (auch nicht das).
  6. Aber Aktion ist das, was wir brauchen, wählen Sie die Art der Aktion Debugger-Befehl.
  7. Wir schreiben den Ausdruck, den wir ausführen müssen:
  8. Ausdruck cell.desriptionTextOutlet.text = "\ (indexPath.item) Mission abgeschlossen".
  9. Setzen Sie ein Häkchen - Setzen Sie die Ausführung nach erfolgreichem Abschluss des Befehls fort.

Bild

9. Wir versuchen es.

Bild

Dies ist ein Erfolg. Es stellte sich heraus, dass der Text für jede Zelle während der Erstellung der Tabelle geändert wurde, und wir mussten nicht für jede Zelle Zeit opfern und Operationen vorschreiben.

Haltepunktfunktion


Es gibt immer Zeiten, in denen in unserer Anwendung etwas passiert, das wir nicht erklären können, der Text sich nicht oder mehr als nötig ändert. Es scheint, dass Breakpoint in diesem Fall nichts zu sagen hat. Dies ist jedoch nicht ganz richtig. Wenn Sie Obj-C kennen und wissen, welche Methode der Compiler ausführt, die Sie verfolgen möchten, können Sie Breakpoint darauf setzen. Beim nächsten Aufruf der Methode stoppt die Anwendung beim Ausführen von Assembler-Code.

1. Wählen Sie im Haltepunktnavigator die Option Symbolischer Haltepunkt.

Bild

2. Wir möchten die Methode zum Festlegen des Texts in der Zelle verfolgen. Schreiben Sie - [UILabel setText:].

Bild

3. Das Null-Argument existiert nicht und die Zählung beginnt mit dem ersten. Die erste Methode ist nicht das, was wir brauchen (wir setzen die aktuelle Zeit auf die Statusleiste), aber die zweite ist nur unsere:

4. Unter "$ arg1" wird die Beschreibung des Objekts gespeichert.

5. Unter „$ arg2“ wird die Auswahlfunktion gespeichert.

6. Unter "$ arg3" wird der von der Methode erhaltene Text gespeichert.

Ok, das scheint klar zu sein. Manchmal gibt es jedoch Situationen, in denen nicht nur ein Text in der Statusleiste festgelegt werden muss und Sie die Ausführung der Methode in einem bestimmten Controller verfolgen müssen. Was ist zu tun? Sie können Breakpoint ähnlich wie zuvor installiert aktivieren, aber seine Position im Code festlegen. Was bedeutet das? Wir wissen mit Sicherheit, dass unsere Ansicht angezeigt wird, wenn wir den Text in der Zelle installieren. Daher müssen Sie ihn in viewDidLoad oder nach dem Erstellen der Zelle einfügen.

Um einen Haltepunkt zu erstellen, setzen wir ihn in die Zeile und schreiben in der Aktion den folgenden Code:

breakpoint set --one-shot true --name "-[UILabel setText:]” 

breakpoint set —one-shot true - Haltepunkt erstellen
—name ist der Name des —name
“-[UILabel setText:]” aufgerufene Methode

Folgendes ist passiert:

Bild

Zeilen überspringen



Aber was ist, wenn wir den Verdacht haben, dass eine Codezeile unser gesamtes Programm verdirbt? Während der Codeausführung können Sie die Ausführung einer bestimmten Codezeile wie folgt vermeiden:

  1. Wir setzen einen Haltepunkt in eine Zeile, die wir nicht ausführen möchten.
  2. Wenn die Ausführung stoppt, ziehen Sie sie in die Zeile, mit der wir das Programm fortsetzen möchten (lustig, aber es funktioniert nicht immer, die Option ohne Ziehen ist niedriger).

Es gibt auch eine andere Option, die das Überspringen von Zeilen optimiert - dies ist die Vorschrift des entsprechenden Befehls im „Haltepunkt bearbeiten“. Das Team ist riskant, da das Wesentliche bei solchen Sprüngen darin besteht, uns vor dem Wiederaufbau zu bewahren. Wenn Sie jedoch die Initialisierung des Objekts überspringen und versuchen, Kontakt mit ihm aufzunehmen, stürzt das Programm ab.

Bild

Beenden wir unser Programm beim Initialisieren des Bildes und weisen das Bild der Zelle überhaupt nicht zu. Dazu müssen wir fünf Codezeilen überspringen und die Zelle ohne Bild zurückgeben. Dazu überspringen wir die Ausführung der folgenden fünf Codezeilen im aktuellen Thread und setzen das Programm fort:

Bild

Es klingt ziemlich gut, aber ich möchte trotzdem ein Bild zuweisen. Fügen wir dem Haltepunkt eine Zuweisungsmethode hinzu:

Bild

Eine gute Kombination, jetzt haben wir nur noch einen Bildtyp in jeder Zelle.

Watchpoint


Eine weitere praktische Funktion im Debugger ist das Verfolgen von Werten im Programm, Watchpoints. Watchpoint ist KVO etwas ähnlich. Wir setzen einen Haltepunkt, um den Status eines Objekts zu ändern. Jedes Mal, wenn es seinen Status ändert, stoppt der Programmausführungsprozess und wir können den Wert und die Stellen sehen, von denen und von wem der Wert geändert wurde. Zum Beispiel habe ich einen Überwachungspunkt auf eine Zelle gesetzt, um herauszufinden, was passiert, wenn eine Tabelle ausgelagert und eine neue Zelle initialisiert wird. Die Liste der Befehle erwies sich als sehr umfangreich, daher möchte ich nicht nur einige nennen: Ausführung der Layoutansicht in der Zelle und Festlegen von Einschränkungen, Animation, Festlegen von Status für die Zelle und vieles mehr.

Um den Überwachungspunkt auf einen Wert festzulegen, müssen Sie das Haltepunktprogramm im Bereich der zu überwachenden Eigenschaften stoppen, die Eigenschaft im Bereich "Debug-Variable" auswählen und "<Parameter>" auswählen.

Bild

Um den Überwachungspunkt mit einer Variablen zu entfernen, müssen Sie in den Haltepunktnavigator schauen, dort wird zusammen mit dem Rest des Haltepunkts unser Überwachungspunkt sein.

Änderung der Haltepunkt-Benutzeroberfläche


Manchmal müssen wir mehr über das Objekt erfahren, das wir abwehren möchten. Am einfachsten ist es, mit „po“ Informationen zum Objekt anzuzeigen und die Position des Objekts im Speicher an derselben Stelle anzuzeigen. Es kommt jedoch vor, dass wir keinen direkten Link zu einem Objekt haben und es nicht in der API-Ansicht dargestellt wird, auf der die Bibliothek liegt oder möglicherweise verborgen ist. Eine der Optionen ist die Verwendung der Ansichtshierarchie. Dies ist jedoch nicht immer praktisch und es ist nicht immer schwer zu verstehen, dass Sie die gewünschte Ansicht gefunden haben. Sie können versuchen, den folgenden Befehl zu verwenden:

 expression self.view.recursiveDescription() 

Es ist in Obj-C, aber es wurde in Swift aufgrund der Besonderheiten der Sprache entfernt, wir können es nicht tun, aber da Debuger mit Obj-C arbeitet, kann er theoretisch diesen Befehl füttern und er wird verstehen, was Sie von ihm wollen . Um Obj-C-Code in der Konsole auszuführen, müssen Sie den folgenden Befehl eingeben:

 expression -l objc -O - - [`self.view` recursiveDescription] 

Was siehst du hier? Ich sehe eine ziemlich unpraktische Konstruktion, an die man sich mit der Zeit gewöhnen könnte, aber wir sollten es besser nicht tun, sondern Typealien verwenden, um den Befehl zu vereinfachen:

 command alias poc expression -l objc -O — 

Jetzt schrumpft und vereinfacht unser Team, macht aber weiter:

 poc [`self.view` recursiveDescription] 

Funktioniert es nach dem Schließen von Xcode oder in einem anderen Projekt? Leider nein. Aber es kann behoben werden! Indem Sie die .lldbinit-Datei erstellen und dort unseren Alias ​​eingeben. Wenn Sie nicht wissen wie, finden Sie hier die Anleitung zu den Artikeln:

1. Erstellen Sie eine .lldbinit-Datei (Sie können .gitignore als Prototyp verwenden, sie gehört zum gleichen Typ von unsichtbaren Textdateien).

2. Schreiben Sie genau den folgenden Befehl in diese Datei:

  command alias poc expression -l objc -O - - 

3. Legen Sie die Datei im Ordner unter der Adresse "MacintoshHD / Users / <Hier ist der Name Ihres Benutzers>" ab.

Und so erhielten wir eine Beschreibung aller auf dem Bildschirm angezeigten Ansichten. Versuchen wir herauszufinden, was wir mit der Adresse von Objekten im Speicher tun können. Für Swift gibt es eine Methode mit einem Nachteil: Sie müssen den Objekttyp im Speicher immer auf einen bestimmten Wert umwandeln:

 po unsafeBitCast(0x105508410, to: UIImageView.self) 

Jetzt können wir die Position unseres Bildes in der Zelle sehen. Verschieben wir es so, dass es auf der Zelle zentriert ist und einen Einzug an der Seite von 20 px hat.

Bild

Manchmal ist eine Änderung nicht sofort erkennbar, aber es ist erforderlich, die Anwendung aus dem Debug zu entfernen, um die Änderung zu bemerken.

Wenn wir jedoch in jeder Zelle etwas Ähnliches sehen möchten, müssen wir die Ausführung von Befehlen beschleunigen. Wir können mehrere Skripte in Python schreiben, die für uns funktionieren ( Informationen zum Hinzufügen von Skripten finden Sie hier www.raywenderlich.com/612-custom-lldb-commands-in- üben ), und wenn Sie wissen, wie man mit Python umgeht und für lldb darauf schreiben möchten, werden Sie sich als nützlich erweisen.

Ich habe beschlossen, eine Erweiterung für die UIView-Klasse zu schreiben, die die Ansicht einfach in die richtige Richtung verschiebt. Es schien mir, dass es weniger Probleme beim Verbinden neuer Skripte mit LLDB geben würde und für keinen iOS-Programmierer schwierig ist (ansonsten müssen Sie Python für LLDB lernen).

Ich habe nicht nach dem Platz des Objekts im Speicher gesucht und es in die gewünschte Klasse gebracht, damit ich später einen Frame nehmen würde, es würde auch zu viel Zeit in Anspruch nehmen. Die Frage wurde durch Schreiben einer Funktion in der UIView-Erweiterung gelöst:

Bild

Leider funktioniert es nicht gut mit Zellen, höchstwahrscheinlich aufgrund der Tatsache, dass zum Zeitpunkt der Ausführung des Flush-Befehls nicht alle Zellenpositionen berechnet wurden und nicht auf dem Bildschirm angezeigt wurden (wir haben tableViewCell noch nicht zurückgegeben). Mit anderen statischen Elementen funktioniert es gut.

Wenn wir die Position der Ansicht in der Hierarchie kennen, können wir darauf zugreifen und ihre Position ändern.

Und jetzt ist die umgekehrte Situation, wenn wir auf ViewHierarchy zugreifen können und von dort Ansichtsdaten abrufen möchten. In Xcode ist es möglich, die Ansichtshierarchie während der Ausführung eines Programms anzuzeigen. Sie können auch Farben, Layout, Typen und Bindungen für andere Objekte anzeigen, einschließlich dieser. Versuchen wir, auf die Einschränkungen unserer UIImageView zuzugreifen.

So erhalten Sie Einschränkungsdaten:

1. Klicken Sie auf die Debug View Hierarchy.
2. Aktivieren Sie abgeschnittenen Inhalt im Bereich am unteren Bildschirmrand.
3. Aktivieren Sie Einschränkungen im selben Bereich.
4. Wählen Sie Contraint.
5. Klicken Sie im Menü auf Bearbeiten -> Kopieren (Befehl + C).
6. Die Bindung dieser Art wird kopiert: ((NSLayoutConstraint *) 0x2838a39d0).
7. Und jetzt, so wie wir es durch den Code ändern, können Sie es auch in lldb ändern:
expression [((NSLayoutConstraint *)0x2838a39d0) setConstant: 60]
8. Nachdem Sie auf die Schaltfläche Weiter geklickt haben, aktualisiert das Element seine Position auf dem Bildschirm.

Sie können Farben, Text und mehr auf die gleiche Weise ändern:

 expression [(UILabel *)0x102d0a260] setTextColor: UIColor.whiteColor] 

Das Demo-Projekt erwies sich als zu einfach (60 Codezeilen im ViewController). Der größte Teil des von mir geschriebenen Codes wird im Artikel vorgestellt, sodass es keine Schwierigkeiten gibt, das Testprojekt zu reproduzieren.

PS: Wenn Sie Fragen oder Kommentare haben, schreiben Sie. Schauen Sie sich WWDC und Debate as Pro an.

Ich rate Ihnen auch, sich mit den Materialien vertraut zu machen:

Inspiriert von Advanced Debugger WWDC 18 Session
Debugger-Befehle
Hinzufügen von Python-Skripten zu LLDB Xcode

Source: https://habr.com/ru/post/de460779/


All Articles