IOS Как определить, что блокирует пользовательский интерфейс
Я новичок в разработке iOS, но я начинаю понимать некоторые из более сложных понятий. В настоящее время у меня есть приложение, которое реализует AVCam для захвата видео. AVCam создается в отдельном потоке, но использует представление, которое находится в моем основном файле xib. Когда камера завершена, она вызывает полную функцию в моем классе ViewController. В рамках полной функции я вызываю ряд других функций, которые обновляют пользовательский интерфейс, а также несколько NSLogs. Кажется, все работает нормально, я вижу журналы в консоли сразу, но для обновления пользовательского интерфейса требуется еще 3 секунды. Я пробовал использовать инструменты, чтобы найти нарушительный код, но я не могу найти его. Есть ли другой способ определить, что блокирует пользовательский интерфейс?
Вот код, который вызывается, когда запись завершена;
-(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);
}
Все регистрируется немедленно, но прогресс HUD и контроллер модального представления не срабатывают в течение примерно 2 - 5 секунд, это очень странно.
Вот состояние до и после потоков (когда оно заморожено, а когда оно разморожено).
![enter image description here]()
![enter image description here]()
Ответы
Ответ 1
Попробуйте приостановить выполнение программы (есть кнопка для нижней панели Xcode
, третья)
![Pause]()
- Затем посмотрите на левую панель (
Navigator panel
),
- Найти
Debug Navigator
![Debug Navigator]()
- Найти поток с помощью функции
main
и mb, которую вы можете определить методами в этом потоке, что так долго требуется для обновления вашего пользовательского интерфейса. Метод, который работает прямо сейчас, является верхним черным обычно (с внутренними методами obj-c
с серым цветом).
![main]()
Ответ 2
Вы можете использовать инструмент System Trace в инструментах, запустив приложение в режиме профиля. Затем вы получите подробное описание всех потоков в системе, а также трассировки стека при каждом событии планирования, через которое проходит поток.
Есть отличное видео с WWDC System Trace in Depth 2016 года, которое поможет вам отладить проблему заблокированных потоков.
Это намного лучше, чем инструмент Time Profiler, поскольку этот инструмент работает на основе выборок того, что выполняется на процессоре через определенные промежутки времени. Однако, если ваш поток заблокирован, он не работает на процессоре, поэтому - он не будет выбран. Возможно, ваш главный поток заблокирован на целую секунду, но он не будет отображаться в Time Profiler.
Ответ 3
Вы можете использовать Time Profiler, чтобы узнать, что блокирует ваше приложение.
Ответ 4
Совет Михаэля Куэно замечательный - описаны профилирование и "интересные места" System Trace.
Еще один инструмент для этого в iOS 12+, использующий указатели: https://pspdfkit.com/blog/2018/using-signposts-for-performance-tuning-on-ios/
Идея заключается в том, что вы используете функцию os_signpost
из инфраструктуры os
и вставляете ее во все места, которые, как вы подозреваете, блокируют основной поток.
Скажем, вы нажимаете UIButton, а иногда он отстает.
Вы должны вставить os_signpost
в обработчик buttonPressed
и во все функции, которые вы подозреваете.
Затем вы должны профилировать в инструментах, используя шаблон Blank
и добавляя суб-шаблон os_signpost
. Пример здесь: https://github.com/gatamar/UnsplashSearch.
![enter image description here]()
Обратите внимание на различия API в Swift/Objc:
Свифт:
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);
Ответ 5
Если у вас есть проблема блокировки пользовательского интерфейса на симуляторе:
Прежде чем углубиться в любой из других подходов, попробуйте полностью симулировать, удалить приложение и заново перестроить/запустить приложение, в моем случае я не смог найти ни одной проблемы с потоком или сбоя почти через час копаясь в инструментах, я просто подумал, что это может быть проблема с симулятором
Ответ 6
Мне нравится использовать эту функцию:
sleep(x);
где "x" - это количество секунд... он просто блокирует любой поток, который он запускает за это количество секунд. Если ваш пользовательский интерфейс зависает, вы знаете, что заблокировали основной поток и, таким образом, этот код запускается в основном потоке (независимо от того, планируете ли вы это или нет). Попробуйте разместить этот вызов в разных местах вашего кода, и он поможет вам определить, что происходит. Надеюсь, что это поможет.