有没有解决方案在iOS上使用最近的Xcode(7.x)进行功能/方法级别的分析?
我的意思是等同于GCC's -pg
,它使编译器将性能记录到您的代码中。当Apple仍在使用GCC时,我确实在iOS上成功使用了-pg
和gprof
,但似乎没有与clang等效的内容。
我需要找出谁在某种情况下微阻挡我的主线程(应用程序仍然会做出反应,但阻塞会使滚动抖动)。遗憾的是,Instruments的工具无法胜任任务:取样(停止应用程序并记录堆栈跟踪)对于我的需求来说太粗糙/不精确。
所以我需要一种方法来找出哪个方法在什么时间和多长时间运行,正好。唯一真正的方法是让编译器注入必要的代码(这是-pg
正在做的事情),或者是对Objective-C运行时的一些创造性的黑客攻击。有没有解决方案?
答案 0 :(得分:0)
@MikeDunlavey关于设置计时器的建议对我来说是正确的解决方案。真正的计时器在我的情况下不起作用,所以我使用了具有高优先级的后台线程和NSCondition
(像pthread_cond_timedwait
这样的低级机制也可以工作)。每次runloop迭代时,都会触发条件。如果主线程花费的时间太长,则条件将中止。
这是我用过的非常粗糙的代码。由于我的问题是在非常繁忙的创业公司,这足以让我发现我的问题;如果你想在“普通”运行时使用它来检测问题,你需要增强它以处理runloop的等待部分。
但是,我无法解决这个解决方案的所有问题;滚动仍然有点紧张,但它比以前更好。- (void)startWatchdog
{
static NSDate * lastIteration;
static BOOL hasHandled = NO;
NSCondition * condition = [[NSCondition alloc] init];
lastIteration = [NSDate date];
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL,
kCFRunLoopBeforeTimers | kCFRunLoopBeforeWaiting, true, 0,
^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSDate * now = [NSDate date];
if (activity == kCFRunLoopBeforeTimers) {
if (!hasHandled) {
[condition lock];
[condition signal];
[condition unlock];
}
lastIteration = now;
hasHandled = NO;
} else {
// About to wait for events. We might want tell the watchdog method
// that it's OK that there's going to be a timeout.
[condition lock];
[condition signal];
[condition unlock];
hasHandled = YES;
}
}
);
NSThread * watchdog = [[NSThread alloc] initWithTarget:self selector:@selector(watchdog:) object:condition];
[watchdog setThreadPriority:1];
[watchdog start];
CFRunLoopRef runloop = [[NSRunLoop currentRunLoop] getCFRunLoop];
CFRunLoopAddObserver(runloop, observer, kCFRunLoopCommonModes);
CFRunLoopAddObserver(runloop, observer, (CFStringRef)UITrackingRunLoopMode);
}
- (void)watchdog:(NSCondition *)condition
{
@autoreleasepool {
while (1) {
BOOL wasHandled;
NSDate * start = [NSDate date];
[condition lock];
wasHandled = [condition waitUntilDate:[start dateByAddingTimeInterval:0.2]];
[condition unlock];
if (!wasHandled) {
NSLog(@"-- Timeout: %f", [[NSDate date] timeIntervalSinceDate:start]);
}
}
}
}