将 NSTimer 放在单独的线程中 [英] Placing an NSTimer in a separate thread

查看:22
本文介绍了将 NSTimer 放在单独的线程中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:可能值得向下滚动以阅读我的编辑.

Note: It's probably worth scrolling down to read my edit.

我正在尝试在单独的线程中设置 NSTimer,以便在用户与我的应用程序的 UI 交互时它会继续触发.这似乎有效,但 Leaks 报告了许多问题 - 我相信我已经将其范围缩小到我的计时器代码.

I'm trying to setup an NSTimer in a separate thread so that it continues to fire when users interact with the UI of my application. This seems to work, but Leaks reports a number of issues - and I believe I've narrowed it down to my timer code.

目前发生的事情是 updateTimer 尝试访问绑定到我的应用程序界面中的 NSTableView 的 NSArrayController (timersController).从那里,我获取第一个选定的行并更改其 timeSpent 列.注意:timersController 的内容是通过 Core Data 生成的托管对象的集合.

Currently what's happening is that updateTimer tries to access an NSArrayController (timersController) which is bound to an NSTableView in my applications interface. From there, I grab the first selected row and alter its timeSpent column. Note: the contents of timersController is a collection of managed objects generated via Core Data.

通过阅读,我相信我应该尝试在主线程上执行 updateTimer 函数,而不是在我的计时器辅助线程中执行.

From reading around, I believe what I should be trying to do is execute the updateTimer function on the main thread, rather than in my timers secondary thread.

我在这里发帖是希望有更多经验的人可以告诉我这是否是我做错的唯一一件事.阅读 Apple 关于线程的文档后,我发现它是一个非常大的主题领域.

I'm posting here in the hopes that someone with more experience can tell me if that's the only thing I'm doing wrong. Having read Apple's documentation on Threading, I've found it an overwhelmingly large subject area.

NSThread *timerThread = [[[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil] autorelease];
[timerThread start];

-(void)startTimerThread
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    activeTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES] retain];

    [runLoop run];
    [pool release];
}
-(void)updateTimer:(NSTimer *)timer
{
    NSArray *selectedTimers = [timersController selectedObjects];
    id selectedTimer = [selectedTimers objectAtIndex:0];
    NSNumber *currentTimeSpent = [selectedTimer timeSpent];

    [selectedTimer setValue:[NSNumber numberWithInt:[currentTimeSpent intValue]+1] forKey:@"timeSpent"];
}
-(void)stopTimer
{
    [activeTimer invalidate];
    [activeTimer release];
}

更新

对于这次泄漏,我仍然完全迷失了方向.我知道我显然做错了什么,但我已经将我的应用程序剥离到它的骨架,但似乎仍然无法找到它.为简单起见,我已将我的应用程序控制器代码上传到:a small pastebin.请注意,我现在删除了计时器线程代码,而是选择在单独的运行循环中运行计时器(如此处所建议的).

I'm still totally lost with regards to this leak. I know I'm obviously doing something wrong, but I've stripped my application down to its bare bones and still can't seem to find it. For simplicities sake, I've uploaded my applications controller code to: a small pastebin. Note that I've now removed the timer thread code and instead opted to run the timer in a separate runloop (as suggested here).

如果我将泄漏调用树设置为隐藏缺少的符号和系统库,则会显示以下输出:

If I set the Leaks Call Tree to hide both Missing Symbols and System Libraries, I'm shown the following output:

屏幕截图链接已损坏并已删除.

Links to screenshots broken and therefor removed.

推荐答案

如果你产生一个新线程的唯一原因是让你的计时器在用户与 UI 交互时运行,你可以将它添加到不同的 runloop模式:

If the only reason you are spawning a new thread is to allow your timer to run while the user is interacting with the UI you can just add it in different runloop modes:

NSTimer *uiTimer = [NSTimer timerWithTimeInterval:(1.0 / 5.0) target:self selector:@selector(uiTimerFired:) userInfo:nil repeats:YES];      
[[NSRunLoop mainRunLoop] addTimer:uiTimer forMode:NSRunLoopCommonModes];

作为此答案的补充,现在可以使用 Grand Central Dispatch 和块来安排计时器:

As an addendum to this answer it is now possible to schedule timers using Grand Central Dispatch and blocks:

// Update the UI 5 times per second on the main queue
// Keep a strong reference to _timer in ARC
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, (1.0 / 5.0) * NSEC_PER_SEC, 0.25 * NSEC_PER_SEC);

dispatch_source_set_event_handler(_timer, ^{
    // Perform a periodic action
});

// Start the timer
dispatch_resume(_timer);

稍后不再需要计时器时:

Later when the timer is no longer needed:

dispatch_source_cancel(_timer);

这篇关于将 NSTimer 放在单独的线程中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆