如何在iOS中设置动画线程?

时间:2013-03-17 01:11:03

标签: ios multithreading animation nsthread runloop

我有一个函数drawView,它是线程安全的,可以用于短时间的游戏动画。我有函数startAnimatingstopAnimating。我希望后台线程以常规速率调用drawView,但仅在启用动画期间。

startAnimating我打算调用视图performSelectorInBackground:withObject:来运行该线程。

我对如何进行线程通信和初始化绘图线程有点困惑:具体来说,设置一个runloop来接收显示链接消息,然后在最后通知线程它应该退出并退出运行循环从主线程调用stopAnimating时干净利落地。我想确保drawView之后永远不会调用stopAnimating,并且在绘图操作过程中不会突然取消绘图线程。我在网上看到了很多非常糟糕的答案。

1 个答案:

答案 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的原因是因为运行循环可能无法及时返回,但调用选择器会强制它返回