如何调用main thread以更新UI,如何使用代码块block code

之前在写一个iPhone游戏的时候遇到过这么一个问题。

因为是一个联机游戏,考虑到网络性能当然要使用socket,又因为是回合制,所以自然而然的想到了使用多线程并阻塞连接接收socket信息。

问题来了,在接受到信息后准备更新UI的时候发生线程交叉的错误,这也是意料之中,非主线程自然不能更新UI。
想了想,有了如下几个解决办法。

方案1:直接获取主线程,执行代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if ([NSThread isMainThread])
    {
        // 如果当前已经在主线程下了
        // 做你该做的事儿,或者这个主线程的判断你也可以干错忽略掉
    }
    else
    {
        // if not main thread, get main thread in order to update UI elements
        dispatch_async(dispatch_get_main_queue(), ^{
            // 更新你的UI元素
            // 或者任何应该在主线程下做的工作
            }
        });
    }

方案2:使用系统自带的调用方法

performSelectorOnMainThread:withObject:waitUntilDone:

1
2
// 这个将使用main thread来调用selector
[target performSelectorOnMainThread:(SEL)selector withObject:nil waitUntilDone:FALSE];

顺被在这里提一下,performSelector有很多中方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 这个将使用当前thread来调用selector
// 当前线程将在收到这条信息之后立即发送调用selector的消息
[target performSelector:(SEL)selector withObject:nil];
 
// 这个将在延时结束后发送调用消息
// 要注意的是
// 1. 时间并不是100%准确。 假设你延时1秒后执行,可能1.001秒后执行
// 2. 此方法需要run loop的支持。 意思就是如果你在你自定义的thread中执行无效
[target performSelector:(SEL)selector withObject:nil afterDelay:1];
/*
* run loop是苹果提出的一种处理线程是的机制。与其他编程语言不同,苹果认为线程
* 的使用应该受到格外的重视。因为一个线程的创建将调用大量的系统资源,所有与硬件
* 打交道的方法都将有可能被调用。那么一旦你创建了一个线程就应该让这个线程尽量的
* 多存活一会而,让它尽量的去工作。所以,run loop产生了,在线程被创建后,相应
* run loop也应该被创建以确保这个线程在没有任务可以执行的时候空转,也就是啥也
* 不做直到有新的任务。一个iPhone在创建之后一个run loop就跟着主线程同时被创建
* 了,所以performSelector:方法其实就是把这个selector加入到了主线程的run loop
* 中等待执行,可是如果是你手动创建了一个线程,却又没有创建相应的run loop,那么
* 即便使用performSelector加入到执行队列中的任务也会在线程结束后立即消亡。
* 这也就是为什么使用延迟调用时要么在主线程下,要么你自己写好一个run loop。
*/

方案3:回调

说是回调,其实也不是,就是写了一个回调的代码块,仅供大家学习。

1
2
3
4
5
char* startProgram( int p1, int p2, void(^reportBackToUI)(int) )
{
    doSomeJob();
    reportBackToUI( someResults ); // someResults是一个int型参数
}

接下来,这么使用这个方法。

1
2
3
4
5
6
return startProgram(520, 1314, ^(int someResults) {
           dispatch_async(dispatch_get_main_queue(), ^{
              // 我们可以在这里让main thread来执行语句
              // Update UI in some way.
           });        
       });

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s