web-dev-qa-db-fra.com

Comment enregistrer toutes les méthodes utilisées dans l'application iOS

Je suis en train de développer une application iPad pour un client. Beaucoup de travail a déjà été fait et j'essaie de comprendre comment tout cela est conçu pour fonctionner.

Une des choses que j'aimerais faire est de consigner les méthodes qui sont appelées lors de l'exécution de l'application. J'ai vu un script DTrace personnalisé conçu pour consigner toutes les méthodes du démarrage, mais lorsque je l'exécute dans Instruments, je n'obtiens aucun résultat.

Quelle est la meilleure façon de consigner les méthodes?

41
Phil John

Inspiré par la réponse de tc à une question similaire ici , je réunis une action de point d'arrêt de débogage qui déconnectera le nom de la classe et de la méthode chaque fois que l'objc_msgSend () est déclenché dans votre application. Cela fonctionne de manière similaire au script DTrace que j'ai décrit dans cette réponse .

Pour activer cette action, créez un nouveau point d'arrêt symbolique (sous Xcode 4, accédez au navigateur de point d'arrêt et créez un nouveau point d'arrêt symbolique à l'aide du signe plus en bas à gauche de la fenêtre). Définissez le symbole objc_msgSend, configurez-le pour qu'il se poursuive automatiquement après l'évaluation des actions et définissez-le comme une commande de débogage à l'aide de ce qui suit:

printf "[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)),*(long *)($esp+8)

Votre point d'arrêt devrait ressembler à ceci:

Breakpoint action

Cela devrait déconnecter les messages comme celui-ci lors de l'exécution avec votre application:

[UIApplication sharedApplication]
[UIApplication _isClassic]
[NSCFString getCString:maxLength:encoding:]
[UIApplication class]
[SLSMoleculeAppDelegate isSubclassOfClass:]
[SLSMoleculeAppDelegate initialize]

Si vous vous demandez où j'ai extrait les adresses de mémoire, lisez cet article de Phrack sur les internes d'exécution d'Objective-C. Les adresses de mémoire ci-dessus ne fonctionneront que sur le simulateur, vous devrez donc peut-être modifier ce paramètre pour qu'il fonctionne avec les applications des périphériques iOS. Collin suggère la modification suivante dans sa réponse pour l'exécuter sur un périphérique:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

De plus, je pense que vous verrez que la déconnexion de chaque méthode appelée dans votre application vous submergera d'informations. Vous pourrez peut-être utiliser certaines conditions pour filtrer cela, mais je ne sais pas si cela vous aidera à savoir comment votre code s'exécute.

54
Brad Larson

Si vous utilisez LLDB, vous devrez utiliser les commandes de débogage suivantes. Celles-ci ont été testées dans Xcode 4.6.

Dispositif:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($r0),$r1)

Simulateur:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName(*(long*)($esp+4)), *(long *)($esp+8))
17
warhammerkid

Pour tracer le code de l'application sous Xcode 6 sur le périphérique, je devais utiliser l'expression de débogueur suivante.

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($arg1),$arg2)
5

L'approche de Brad Larson peut être adaptée pour fonctionner sur le périphérique à l'aide de la commande debugger:

printf "[%s %s]\n", (char *)object_getClassName($r0),$r1

Plus d'informations peuvent être trouvées dans la note technique ici: notes techniques

4
Collin

les versions ultérieures de xcode vous devez appeler comme ça 

expr -- (void)printf("[%s, %s]\n",(char *) object_getClassName(*(long*)($esp+4)), (char *) *(long *)($esp+8) )
3
Ali Kıran

Si vous souhaitez limiter la sortie aux seuls messages envoyés à une classe, vous pouvez ajouter une condition comme celle-ci.

(int) strcmp ((char *) object_getClassName ($ r0), "NSString") == 0

2
Jeff

Si vous souhaitez consigner des méthodes dans le simulateur sur 64 bits, utilisez plutôt la commande suivante:

expr -- (void) printf("[%s %s]\n", (char *)object_getClassName($rdi), (char *) $rsi)

Ou si cela ne fonctionne pas, enregistrez-le de cette façon:

 enter image description here

L'idée principale est d'utiliser $ rdi pour l'objet (self) et $ rsi pour le sélecteur.

1
TGO

Un collègue développeur m'a appris à ajouter les deux mêmes instructions de journal à chaque méthode. Un comme la première ligne, l'autre comme la dernière ligne. Je pense qu'il a un script qui le fait automatiquement pour ses projets, mais le résultat est:

NSLog(@"<<< Entering %s >>>", __PRETTY_FUNCTION__);
NSLog(@"<<< Leaving %s >>>", __PRETTY_FUNCTION__);

Au niveau de la console, ceci créera quelque chose comme:

 <<< Entering -[MainListTableViewController viewDidLoad] >>>

Très utile pour suivre ce qui se passe.

1
DenVog