我有一个函数drawView
,它是线程安全的,可以用于短时间的游戏动画。我有函数startAnimating
和stopAnimating
。我希望后台线程以常规速率调用drawView
,但仅在启用动画期间。
在startAnimating
我打算调用视图performSelectorInBackground:withObject:
来运行该线程。
我对如何进行线程通信和初始化绘图线程有点困惑:具体来说,设置一个runloop来接收显示链接消息,然后在最后通知线程它应该退出并退出运行循环从主线程调用stopAnimating
时干净利落地。我想确保drawView
之后永远不会调用stopAnimating
,并且在绘图操作过程中不会突然取消绘图线程。我在网上看到了很多非常糟糕的答案。
答案 0 :(得分:0)
好好整晚看完Apple页面后,我终于用这段代码解决了它:
// object members
NSThread *m_animationthread;
BOOL m_animationthreadrunning;
- (void)startAnimating
{
//called from UI thread
DEBUG_LOG(@"creating animation thread");
m_animationthread = [[NSThread alloc] initWithTarget:self selector:@selector(animationThread:) object:nil];
[m_animationthread start];
}
- (void)stopAnimating
{
// called from UI thread
DEBUG_LOG(@"quitting animationthread");
[self performSelector:@selector(quitAnimationThread) onThread:m_animationthread withObject:nil waitUntilDone:NO];
// wait until thread actually exits
while(![m_animationthread isFinished])
[NSThread sleepForTimeInterval:0.01];
DEBUG_LOG(@"thread exited");
[m_animationthread release];
m_animationthread = nil;
}
- (void)animationThread:(id)object
{
@autoreleasepool
{
DEBUG_LOG(@"animation thread started");
m_animationthreadrunning = YES;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
CADisplayLink *displaylink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkAction:)];
[displaylink setFrameInterval:3];
[displaylink addToRunLoop:runLoop forMode:NSDefaultRunLoopMode];
while(m_animationthreadrunning)
{
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
DEBUG_LOG(@"runloop gap");
}
[displaylink removeFromRunLoop:runLoop forMode:NSDefaultRunLoopMode];
DEBUG_LOG(@"animation thread quit");
}
}
- (void)quitAnimationThread
{
DEBUG_LOG(@"quitanimationthread called");
m_animationthreadrunning = NO;
}
- (void)displayLinkAction:(CADisplayLink *)sender
{
DEBUG_LOG(@"display link called");
//[self drawView];
}
我使用行[self performSelector:@selector(quitAnimationThread) onThread:m_animationthread withObject:nil waitUntilDone:NO]
而不是简单地在m_animationthreadrunning = NO
中设置stopAnimating
的原因是因为运行循环可能无法及时返回,但调用选择器会强制它返回