Comment définir un point d'arrêt conditionnel dans Xcode en fonction d'une propriété de chaîne d'objet?

90

Je cherche à pouvoir interrompre le débogueur lorsqu'il atteint une correspondance de chaîne particulière. À titre d'exemple, je pourrais avoir quelque chose comme ceci:

Foo myObj = [self gimmeObj];

myObjpourrait avoir une propriété appelée name. Je veux que le débogueur s'arrête sur l'affectation lorsque

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

Comment puis-je définir mon point d'arrêt conditionnel dans Xcode pour ce faire?

Coocoo4Cocoa
la source

Réponses:

184

Vous pouvez définir un point d'arrêt conditionnel dans Xcode en définissant le point d'arrêt normalement, puis cliquez dessus tout en maintenant la touche Contrôle enfoncée et sélectionnez Modifier le point d'arrêt (choisissez Exécuter -> Afficher -> Points d'arrêt).

Dans l'entrée de point d'arrêt, il y a une colonne Condition.

Maintenant, il y a plusieurs problèmes à garder à l'esprit pour la maladie. Premièrement, gdb ne comprend pas la syntaxe des points, donc au lieu de myObj.name, vous devez utiliser [myObj name] (sauf si name est un ivar).

Ensuite, comme pour la plupart des expressions dans gdb, vous devez lui indiquer le type de résultat renvoyé, à savoir "BOOL". Alors définissez une condition comme:

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

Souvent, il est en fait plus facile de faire cela dans le code en ajoutant temporairement du code comme:

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

puis définissant le point de rupture sur le NSLog. Alors votre condition peut être arbitrairement complexe sans avoir à vous soucier de ce que gdb peut et ne peut pas analyser.

Peter N Lewis
la source
11
Sauf qu'en modifiant votre code vous courez le risque d'oublier de supprimer votre journalisation ou de modifier votre comportement
Pål Brattberg
3
C'est vrai. J'atténue souvent cela en ajoutant "NYI" (pas encore implémenté) à la chaîne, puis ma recherche de vérification de pré-publication pour NYI l'attrapera.
Peter N Lewis
17
Pour que cela fonctionne, j'ai dû mettre (bool) en majuscule comme (BOOL), probablement une chose LLDB.
Wex
1
bool ne fonctionnait pas pour moi dans GDB, j'ai dû utiliser BOOL ou int - la différence est expliquée ici stackoverflow.com/a/544250/725871 .
Chaosphere2112
2
Vous ne pouvez pas le mettre dans le code si vous avez un bogue de jeu une fois tous les 200 qui est finalement survenu, et maintenant vous devez faire un point d'arrêt conditionnel. Arrêter le programme pour modifier le code n'est pas une option.
Almo
17

Voici comment utiliser les points d'arrêt conditionnels XCode lldb.

Tout d'abord, double-cliquez sur le point de rupture (ou clic droit edit breakpoint), vous pouvez voir une fenêtre de dialogue.

entrez la description de l'image ici

Voici ce que signifie cette option:

  1. Condition : le point d'arrêt ne se déclenchera que dans cette condition.
  2. Ignorer : le nombre de fois que la condition doit satisfaire avant de déclencher le point d'arrêt
  3. Action : action qui s'exécute après la rupture du point d'arrêt.
  4. Options : continuer automatiquement après avoir évalué les actions

Voici un résumé. Pour l'exemple ci-dessus en image, cela signifie que lorsque la variable buildingIdest égale à 13, coupez ici. Si j'ajoute le temps d'ignorer à 1, alors il ignorera la première fois quand buildingIdest égal à 13 et se cassera à la deuxième fois que la condition est remplie.

Pour les actions, lorsque vous appuyez sur Ajouter des actions, il y aura une liste de choix. Habituellement, ce que je fais est d'utiliser les Debugger Command povariables pour imprimer que je dois vérifier et je pense qu'il existe de meilleures façons d'utiliser les actions que moi.

Il semble que vous deviez recompiler et exécuter l'application si vous modifiez les conditions au moment de l'exécution

nuynait
la source
Probablement parce que la question portait sur l'arrêt au point d'arrêt basé sur une valeur de chaîne [je n'étais pas le contre-votant]
ZS
1
Merci, très utile. Cette réponse mérite plus de votes.
andreskwan
7

Je ne sais pas si cela fonctionnera, mais vous pouvez essayer de définir un point d'arrêt sur cette ligne de code, ouvrir la console du débogueur (Cmd + Shift + R) et taper

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

Où N est remplacé par le numéro du point d'arrêt (un entier).

Adam Rosenfield
la source
2

Si vous mutez myObj.name à l'aide du setter, vous pouvez ajouter un point d'arrêt symbolique -[MyObjClass setName:]soit à partir de la console de débogage, soit à partir du menu Exécuter-> Gérer les points d'arrêt- > Ajouter un point d'arrêt symbolique dans Xcode. Si non (pourquoi pas? Vous ne devriez probablement pas modifier la variable d'instance directement sauf dans l'initialiseur ou le dealloc désigné), vous pouvez définir un point de vue dans gdb (utilisez la console de débogage dans Xcode une fois que le débogueur est en cours d'exécution). Cette page explique comment. Je ne pense pas que Xcode expose une interface utilisateur pour définir des points de surveillance sans utiliser la console de débogage.

Barry Wark
la source
0

Parfois, lorsque vous travaillez avec Frameworks (versions de débogage) et que vous devez placer un point d'arrêt dans certains fichiers / emplacements difficiles à naviguer ou qui ne sont pas exposés publiquement dans le cadre en cours de développement. Une option consiste à écrire une classe d'assistance pour déclencher des points d'arrêt conditionnels et faciliter les étapes d'entrée / sortie.

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

Déclaration d'en-tête dans le cadre en cours de développement.

#import <Foundation/Foundation.h>

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

Et dossier d'implémentation:

#import "DebugConditionalBreakPointHelper.h"

@implementation DebugConditionalBreakPointHelper
+ (void)breakPointCondition:(BOOL)enabled comment:(NSString *)comment {
    if (enabled)
    {
        NSLog(@"Triggerred Conditional Break Point. Comment: %@");
    }
}
@end
lal
la source