1

我有一个drawView线程安全的函数,可以在短时间内绘制游戏动画。我有函数startAnimatingstopAnimating. 我希望后台线程以drawView固定速率调用,但仅在启用动画期间调用。

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

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

4

1 回答 1

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 = NOstopAnimating原因是因为运行循环可能不会及时返回,但调用选择器会强制它返回。

于 2013-03-17T08:34:10.133 回答