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

查看:123
本文介绍了将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.

我在这里发布希望有更多经验的人可以告诉我,如果这是唯一的东西'做错了。阅读关于Threading的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];
}

UPDATE

我仍然完全失去了关于这个泄漏。我知道我明显做错了事,但我已经剥离了我的应用程序到它的裸骨骼,仍然似乎找不到它。为了简单起见,我已将我的应用程序控制器代码上传到:一个小的pastebin 。注意,我现在已经删除了计时器线程代码,而是选择在单独的runloop中运行计时器(如此处所示)。

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:

编辑:已删除的屏幕截图链接。 / p>

Links to screenshots broken and therefor removed.

推荐答案

如果你生成一个新线程的唯一原因是允许你的定时器运行时,可以只是将其添加到不同的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和块来安排计时器: / p>

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天全站免登陆