web-dev-qa-db-fra.com

iOS Comment déterminer ce qui bloque l'interface utilisateur

Je suis assez nouveau dans le développement iOS mais je commence à comprendre certains des concepts les plus compliqués. J'ai actuellement une application qui implémente une AVCam pour capturer des vidéos. L'AVCam est créé sur un thread séparé, mais utilise une vue qui se trouve dans mon fichier xib principal. Lorsque la caméra a terminé la capture, elle appelle une fonction complète dans ma classe ViewController. Dans la fonction complète, j'appelle un certain nombre d'autres fonctions qui mettent à jour l'interface utilisateur ainsi que quelques NSLogs. Tout semble fonctionner correctement, je vois les journaux dans la console immédiatement, mais l'interface utilisateur prend encore 3 secondes pour se mettre à jour. J'ai essayé d'utiliser des instruments pour trouver le code incriminé, mais je n'arrive pas à le trouver. Existe-t-il un autre moyen de déterminer ce qui est bloqué par l'interface utilisateur?

Voici le code appelé lorsque l'enregistrement est terminé;

-(void)movieRecordingCompleted{
       [HUD hide:YES];
        NSLog(@"movieRecordingCompleted");
        [self showModalViewController];
        NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.mov"];
        NSLog(@"pathToMovie: %@", pathToMovie);
        pathToTreatedVid = pathToMovie;
        NSLog(@"File Save Called");
        UISaveVideoAtPathToSavedPhotosAlbum(pathToMovie, nil, NULL, NULL);
}

Tout est enregistré immédiatement, mais le HUD de progression et le contrôleur de vue modale ne se déclenchent pas pendant environ 2 à 5 secondes, c'est très étrange.

Voici l'état avant et après des threads (quand il est gelé vs quand il devient non gelé). enter image description hereenter image description here

26
user379468

Essayez de suspendre l'exécution du programme (il y a un bouton pour cela dans le panneau inférieur de Xcode, le troisième)

Pause

  • Regardez ensuite le panneau de gauche (Navigator panel),
  • Trouver Debug Navigator

Debug Navigator

  • Trouvez le fil avec la fonction main, et mb, vous pouvez comprendre par les méthodes de ce fil, ce qui prend si longtemps pour mettre à jour votre interface utilisateur. La méthode qui fonctionne actuellement est généralement la plus noire (avec la couleur grise répertoriée obj-c méthodes internes).

main

47
Ossir

Vous pouvez utiliser l'outil System Trace dans Instruments en exécutant votre application en mode profil. Ensuite, vous obtiendrez un aperçu détaillé de tous les threads du système ainsi que des traces de pile à chaque événement de planification traversé par le thread.

Il y a une excellente vidéo de la WWDC 2016 System Trace in Depth qui vous guidera à travers le débogage d'un problème de thread bloqué.

C'est bien meilleur que l'instrument Time Profiler car cet outil fonctionne en prenant des échantillons de ce qui fonctionne sur le CPU à intervalles réguliers. Cependant, si votre thread est bloqué, il ne fonctionne pas sur le CPU, donc - il ne sera pas échantillonné. Votre thread principal peut être bloqué pendant une seconde entière, mais il n'apparaîtra pas dans Time Profiler.

13
Michael Cueno

Vous pouvez utiliser Time Profiler pour découvrir ce qui bloque votre application.

7
Cagdas Altinkaya

Le conseil de Michael Cueno est merveilleux - le profilage System Trace et les "points d'intérêt" sont décrits.

Pourtant, il existe un autre instrument pour le faire dans iOS 12+, en utilisant des panneaux indicateurs: https://pspdfkit.com/blog/2018/using-signposts-for-performance-tuning-on-ios/

L'idée est que vous utilisez la fonction os_signpost du framework os, et insérez-le à tous les endroits que vous soupçonnez de bloquer le thread principal.

Dites, vous appuyez sur UIButton et parfois il traîne. Vous devez insérer os_signpost dans le gestionnaire buttonPressed et dans toutes les fonctions que vous soupçonnez.

Ensuite, vous devez profiler dans Instruments, en utilisant le modèle Blank et en ajoutant os_signpost sous-modèle. Un exemple est ici: https://github.com/gatamar/UnsplashSearch .

enter image description here

Notez les différences d'API dans Swift/Objc:

Rapide:

import os

...

static let pointsOfInterest = OSLog(subsystem: "com.Apple.SolarSystem", category: .pointsOfInterest)
os_signpost(.begin, log: ViewController.pointsOfInterest, name: "createSubviews")
defer {
    os_signpost(.end, log: ViewController.pointsOfInterest, name: "createSubviews")
}

Objc:

#include <os/log.h>
#include <os/signpost.h>

os_log_t log = os_log_create("com.Apple.SolarSystem", "YourCategory");
os_signpost_id_t spid = os_signpost_id_generate(log);

...

os_signpost_interval_begin(log, spid, "func1");

... 

os_signpost_interval_end(log, spid, "func1);
1
Olha Pavliuk

Si vous avez problème de blocage de l'interface utilisateur sur le simulateur:

Avant de plonger dans l'une des autres approches, essayez de tout à fait le simulateur et supprimez l'application et reconstruisez/exécutez à nouveau l'application, dans mon cas, je n'ai pas trouvé de problème de thread ou de crash, après presque un heure de fouille dans les instruments, je pensais juste que cela pourrait être le problème du simulateur et c'était tout :)

0
Shahriar