32

我对 iOS 开发还很陌生,但我开始掌握一些更复杂的概念。我目前有一个实现 AVCam 来捕获视频的应用程序。AVCam 在单独的线程上创建,但使用我的主 xib 文件中的视图。当相机完成捕捉后,它会在我的 ViewController 类中调用一个完整的函数。在完整的函数中,我调用了许多更新 UI 的其他函数以及一些 NSLog。一切似乎都正常,我立即在控制台中看到了日志,但 UI 还需要 3 秒才能更新。我尝试使用工具来查找有问题的代码,但我似乎找不到它。是否有另一种方法来确定 UI 阻止了什么?

这是录制完成时调用的代码;

-(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 秒内没有触发,这很奇怪。

这是线程的前后状态(冻结时与解冻时)。 在此处输入图像描述 在此处输入图像描述

4

6 回答 6

51

尝试暂停程序执行(在底部面板中有一个按钮,Xcode第三个)

暂停

  • 然后查看左侧面板 ( Navigator panel),
  • 寻找Debug Navigator

调试导航器

  • 找到有main函数的线程,mb你可以通过这个线程中的方法弄清楚,更新你的UI需要这么长时间。现在工作的方法通常是顶部黑色的(灰色列出的obj-c内部方法)。

主要的

于 2013-04-10T14:09:03.107 回答
19

您可以通过在配置文件模式下运行您的应用程序来使用 Instruments 中的系统跟踪工具。然后,您将获得系统中所有线程的详细运行情况以及线程经过的每个调度事件的堆栈跟踪。

2016 WWDC System Trace in Depth中有一个很棒的视频,它将引导您调试阻塞的线程问题。

这比Time Profiler工具要好得多,因为该工具的工作原理是每隔一段时间对 CPU 上运行的内容进行采样。但是,如果您的线程被阻塞,它就不会在 CPU 上运行,所以 - 它不会被采样。您的主线程可能被阻塞了一秒钟,但它不会出现在 Time Profiler 中。

于 2017-02-02T01:08:17.460 回答
8

您可以使用Time Profiler找出阻止您的应用程序的原因。

于 2013-04-10T14:07:41.617 回答
6

Michael Cueno 的建议很棒 - 描述了系统跟踪分析和“兴趣点”。

然而,在 iOS 12+ 中还有另一种工具可以使用路标来执行此操作:https ://pspdfkit.com/blog/2018/using-signposts-for-performance-tuning-on-ios/

这个想法是您使用框架中的函数os_signpostos并将其插入您怀疑阻塞主线程的所有位置。

比如说,你按下 UIButton 有时它会滞后。您应该插入处理程序和您怀疑的所有功能os_signpostbuttonPressed

然后,您应该在 Instruments 中配置文件,使用Blank模板并添加os_signpost子模板。一个例子在这里:https ://github.com/gatamar/UnsplashSearch 。

在此处输入图像描述

注意 Swift / Objc 中的 API 差异:

迅速:

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")
}

对象:

#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);
于 2019-09-14T04:55:00.383 回答
1

如果您在模拟器上遇到 UI 阻塞问题

在深入研究任何其他方法之前,尝试完全关闭模拟器并删除应用程序并再次重建/运行应用程序,在我的情况下,我找不到任何线程问题或崩溃,经过近一个小时的仪器挖掘我只是想可能是模拟器问题,就是这样:)

于 2019-09-27T12:03:51.970 回答
-13

我喜欢使用这个功能:

sleep(x);

其中“x”是秒数......它只会阻塞它在该秒数上运行的任何线程。如果您的 UI 冻结,您就知道您阻塞了主线程,因此该代码正在主线程上运行(无论您是否有意)。尝试将此调用放在代码中的不同位置,它应该可以帮助您诊断正在发生的事情。希望有帮助。

于 2013-04-10T14:07:21.623 回答