iOS从后台线程(background thread)发送Notification到主线程(main thread)

iOS从后台线程(background thread)发送Notification到主线程(main thread)

我是iOS的菜鸟一枚,因此在开发的过程就是不断的尝试与摸索。我的问题是这样,我有个后台线程(这个线程是在一个静态库种创建),这个线程负责跟我们的服务器通信,由于负责通信的这个模块(代码)是要在3种平台共享 Windows, Android,Linux,iOS,因此就用c++写的。有人可能想为什么没用Java来写。因为iOS和Java交互起来没有跟C/C++来的那么自然舒畅。

从Objective C调C++的类,实在太方便,跟在C++调用C++没什么区别。但是从C++调Objective C就有点困难,关于这部分,你在网络搜一下,也是有的,方法就是创建一个wrapper类(包裹类或者叫做代理类)。我这里没有用这个方法,因为创建一个中间类,太麻烦了,因为我的那个网络通讯类方法有点多,估计将近100个方法,不想一个个复制粘贴了。我采用的方式是直接把cpp文件改成mm文件,也就是apple的Objective C++,这个就可以C++就可以直接调用Objective C了。

把场景再细化一下,后台通讯模块有了网络事件之后(比如收到一个服务器发过来的包),那么就要更新界面了,界面的有几个,那么把这几个界面的指针都保存一份到 AppDelegate这个类,因为这个类的实例是可以直接通过静态函数得到

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

这样我就不需要在c++代码中保存了,因为我不打算把iOS的那些个基础库的头文件加到c++代码中。

有了AppDelegate的实例,而AppDelegate又有各个View的指针,那么调用view的方法就是顺利成章了。好了,说做就做,接着编译,编译通过,然后执行,没问题,WOW,好高兴,然后改了下界面,再次执行,程序挂了,我了去!什么情况,

后来google半天,才发现,后台线程不可以直接操作界面(前面有提到,网络模块跑在自己的线程中)。这种问题不是每次都出现的,是随机的。

好吧,继续找方法了,继续Google,发现postNotification,关于Notification的部分,apple的官网如是说,

Objects register with a notification center to receive notifications (NSNotification objects) using the addObserver:selector:name:object: or addObserverForName:object:queue:usingBlock: methods. Each invocation of this method specifies a set of notifications. Therefore, objects may register as observers of different notification sets by calling these methods several times.

我靠,这不是正是我要的吗,赶紧在各个view里面注册每个view要处理的notification,

    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center addObserver:self selector:@selector(myResponder:) name:@”myEvent” object:nil];

然后在后台c++代码中直接发送这些notification。

    NSDictionary *lResult = @{ @”suc”:[NSNumber numberWithInt:(int)bSuc],

                               @”result”:[NSString stringWithUTF8String:result.c_str()] };

    NSNotificationCenter *note = [NSNotificationCenter defaultCenter];

    [note postNotificationName:@”myEvent” object:lResult];

,看到post,我下意识的认为他是异步工作(我是直接照搬Windows的PostMessage的工作方式)。结果发现出现同样的问题,程序随机崩溃。后来去apple的网站发现,postNotification是同步进行的,shit,我想问apple,既然是同步为什么不用send而是用post。

关于posNotification,Apple的官方这样说的,

Using the NSNotificationCenter’s postNotification: method and its variants, you can post a notification to a notification center. However, the invocation of the method is synchronous: before the posting object can resume its thread of execution, it must wait until the notification center dispatches the notification to all observers and returns. A notification queue, on the other hand, maintains notifications (instances of NSNotification) generally in a First In First Out (FIFO) order. When a notification rises to the front of the queue, the queue posts it to the notification center, which in turn dispatches the notification to all objects registered as observers

好了,反正apple就是这么做了,我能怎么办,还是找其它方法吧,后来发现 apple 提供了一个异步分发notification,

    dispatch_async(dispatch_get_main_queue(),^{

        [note postNotificationName:@”myEvent” object:lResult];

    });

这个经测试,确实是异步的,哈哈。

除了这个方法,还有另外一种方法,

[self performSelectorOnMainThread:@selector(helperMethod:) withObject:Nil waitUntilDone:NO];

这种方法中需要提供异步调用主线程的方法的名字,上面的例子中就是helperMethod,注意最后一个参数传的No,就是告诉不要等待helperMethod执行完,就返回。关于这个方法我并没有尝试,因为在c++中没办法调用这个方法,因为我的类并不是继承子NSObject,所有并没有performSelectorOnMainThread这个方法。

补充:

今天重新看了这个话题,查看了Apple的官方文件,发现了另外一种方法:

使用NSMachPort

我看了下官方的文档,使用起来有点复杂,具体请参看:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Notifications/Articles/Threading.html#//apple_ref/doc/uid/20001289-CEGJFDFG

 

[正文部分]

 

版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则 按侵权处理.

    分享到:
This entry was posted in Mac/Ios. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*