Jak ustawić warunkowy punkt przerwania w Xcode na podstawie właściwości ciągu obiektu?

93

Chcę mieć możliwość przerwania debugera po osiągnięciu określonego dopasowania ciągu. Jako przykład mogę mieć coś takiego:

Foo myObj = [self gimmeObj];

myObjmoże mieć właściwość o nazwie name. Chcę, aby debugger zatrzymał się przy zadaniu, kiedy

[myObj.name isEqualToString:@"Bar"];

Jak mogę ustawić mój warunkowy punkt przerwania w Xcode, aby to zrobić?

Coocoo4Cocoa
źródło

Odpowiedzi:

184

Możesz ustawić warunkowy punkt przerwania w Xcode, ustawiając go normalnie, a następnie kliknij go z wciśniętym klawiszem Control i wybierz Edytuj punkt przerwania (wybierz Uruchom -> Pokaż -> Punkty przerwania).

We wpisie punktu przerwania znajduje się kolumna Warunek.

W przypadku tego stanu należy pamiętać o kilku kwestiach. Po pierwsze, gdb nie rozumie składni kropek, więc zamiast myObj.name, musisz użyć [myObj name] (chyba że nazwa jest ivar).

Następnie, tak jak w przypadku większości wyrażeń w gdb, musisz podać typ zwracanego wyniku, a mianowicie „BOOL”. Ustaw więc warunek taki jak:

(BOOL)[[myObj name] isEqualToString:@"Bar"]

Często łatwiej jest po prostu zrobić to w kodzie, tymczasowo dodając kod taki jak:

if ( [myObj.name isEqualToString:@"Bar"] ) {
    NSLog( @"here" );
}

a następnie ustawianie punktu przerwania w dzienniku NSLog. Wtedy twój stan może być dowolnie złożony, bez martwienia się o to, co gdb może, a czego nie może przeanalizować.

Peter N Lewis
źródło
12
Tyle, że zmieniając kod, ryzykujesz, że zapomnisz o usunięciu logowania lub zmianie zachowania
Pål Brattberg,
3
To prawda. Często łagodzę ten problem, dodając „NYI” (jeszcze nie zaimplementowano) do ciągu, a następnie moje wyszukiwanie przed wydaniem czeku NYI złapie go.
Peter N Lewis
18
Aby to zadziałało, musiałem utworzyć (bool) wielkie litery jako (BOOL), prawdopodobnie rzecz LLDB.
Wex,
1
bool nie działał dla mnie w GDB, musiałem użyć BOOL lub int - różnica jest wyjaśniona tutaj stackoverflow.com/a/544250/725871 .
Chaosphere2112
2
Nie możesz umieścić tego w kodzie, jeśli masz raz na 200 błędów w grze, który w końcu się pojawił, a teraz musisz zrobić warunkowy punkt przerwania. Zatrzymanie programu w celu zmiany kodu nie wchodzi w grę.
Almo
21

Oto jak to zrobić za pomocą warunkowych punktów przerwania XCode lldb.

Najpierw kliknij dwukrotnie punkt przerwania (lub kliknij prawym przyciskiem myszy edit breakpoint), pojawi się okno dialogowe.

wprowadź opis obrazu tutaj

Oto, co oznaczają te opcje:

  1. Stan : punkt przerwania będzie uruchamiany tylko w tych warunkach.
  2. Ignoruj : ile razy warunek musi zostać spełniony przed uruchomieniem punktu przerwania
  3. Akcja : akcja wykonywana po zerwaniu punktu przerwania.
  4. Opcje : Kontynuuj automatycznie po ocenie działań

Oto podsumowanie. Dla powyższego przykładu na obrazku oznacza to, że gdy zmienna buildingIdjest równa 13, przerwij tutaj. Jeśli dodam czas ignorowania do 1, zignoruje on za pierwszym razem, gdy buildingIdjest równy 13 i zerwie za drugim razem, gdy warunek zostanie spełniony.

W przypadku działań po naciśnięciu przycisku dodaj działania pojawi się lista do wyboru. Zwykle to, co robię, to Debugger Command powypisywanie zmiennych, które muszę sprawdzić i uważam, że są lepsze sposoby wykorzystania akcji niż ja.

Wygląda na to, że musisz ponownie skompilować i uruchomić aplikację, jeśli zmienisz warunki w czasie wykonywania

nuynait
źródło
Prawdopodobnie dlatego, że pytanie dotyczyło zatrzymania się w punkcie przerwania na podstawie wartości ciągu [nie byłem głosującym w dół]
ZS
1
Dzięki, bardzo pomocne. Ta odpowiedź zasługuje na więcej głosów.
andreskwan
7

Nie jestem pewien, czy to zadziała, ale możesz spróbować ustawić punkt przerwania w tym wierszu kodu, otworzyć konsolę debugera (Cmd + Shift + R) i wpisać

condition N (int)[[myObj name] isEqualToString:@"Bar"]

Gdzie N jest zamieniane na numer punktu przerwania (liczba całkowita).

Adam Rosenfield
źródło
2

Jeśli zmutujesz myObj.name przy użyciu metody ustawiającej, możesz dodać symboliczny punkt przerwania w -[MyObjClass setName:]konsoli debugera lub z menu Uruchom-> Zarządzaj punktami przerwania- > Dodaj symboliczny punkt przerwania w Xcode. Jeśli nie (dlaczego nie? Prawdopodobnie nie powinieneś modyfikować zmiennej instancji bezpośrednio, z wyjątkiem wyznaczonego inicjatora lub dealloc), możesz ustawić punkt obserwacyjny w gdb (użyj konsoli debugera w Xcode po uruchomieniu debugera). Ta strona wyjaśnia, jak to zrobić. Nie wierzę, że Xcode udostępnia interfejs użytkownika do ustawiania punktów obserwacyjnych bez korzystania z konsoli debugera.

Barry Wark
źródło
0

Czasami podczas pracy z platformami (kompilacje debugowania) i trzeba umieścić punkt przerwania w pewnym pliku / lokalizacji, w którym trudno jest nawigować lub nie jest on publicznie ujawniany w ramach opracowywanej platformy. Jedną z opcji jest napisanie klasy pomocniczej, która wyzwala warunkowe punkty przerwania i ułatwia wchodzenie / wychodzenie.

- (void)invokeFrameworkMethod {
    ...
    [DebugConditionalBreakPointHelper breakPointCondition:YES comment:@"from invokeFrameworkMethod."];
    ...
}

Deklaracja nagłówka w ramach opracowywanych.

#import <Foundation/Foundation.h>

@interface DebugConditionalBreakPointHelper : NSObject
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment;
@end

I plik wdrożeniowy:

#import "DebugConditionalBreakPointHelper.h"

@implementation DebugConditionalBreakPointHelper
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment {
    if (enabled)
    {
        NSLog(@"Triggerred Conditional Break Point. Comment: %@");
    }
}
@end
lal
źródło