您的位置:首页 > 理论基础 > 计算机网络

iphone线程中使用异步网络的问题,以及如何用NSRunLoop来解决

2016-02-24 10:10 507 查看
就个人经验而言,在iphone线程中使用异步NSURLConnection的经验可以说是一个完全和愉悦搭不上边的事情。他给我带来的麻烦可真不少。例如,前几天,帮客户定位一个问题的时候发生的事情。

事情经过是这样的:客户反馈,无法正常使用我们提供的某个和网络相关的功能,网络回调没有收到。但是其他回调可以正常工作,并且所有回调都是以同样的逻辑放在某个地方的。

我先确认了他的使用方式是否正确,并确认了输入参数的正确性,并且验证了回调的正确设置以及回调函数的使用无误。一切都没有问题,但是就是无法收到回调。

一切都那么的神奇,功能的调用并没有什么特殊的,但是就单单这个功能工作不正常。中间又经过一些确认,发现数据并没有到达服务端。但是同样的使用方式在我们自己的环境下工作又是正常的。

花了将近5个小时,还是没有发现原因,就在我准备放弃的时候,突然想到,莫非他的调用位置是线程中调用?经过确认,发现果然是在线程中调用的!让他们使用performOnMainThread的方式调用,终于解决了问题。

以前遇到过一次在线程中调用异步网络的情况,请教同事,同事告知,异步网络需要自己的RunLoop,所以要在线程中使用异步网络必须有自己的RunLoop,可以将他放到主线程的RunLoop。

但是,这样子,多线程的性能必然被降低,因为这样网络的工作就都是在主线程中完成的。同时怀疑,这样子的网络性能设计不是很低下!

刚好有点时间,就仔细的翻了一下苹果的开发文档,发现其中指出,所有的NSThread都有一个属于自己的NSRunLoop,而NSURLConnection的回调都会回调到当前线程中!

这个和我目前遇到的完全不一样!我无法在当前线程中收到回调!

又仔细在网络上搜索之后发现,原来,是因为网络回调的时候线程的NSRunLoop已经被无效的原因。

我们常见的线程中网络调用是这样的:

- (void)threadFunc

{

NSAutoReleasePool *pool = [NSAutoReleasePool new];

//do something

……



//send your request

[NSURLConnection connectionWithRequest:xxx];

//do some other thing

……

[pool release];

}


一般来说,这个函数会很快走完,线程就结束了。所以,当网络响应回来的时候,你的线程已经结束了。你的网络回调依赖于该线程的NSRunLoop,但是线程已经结束了,所以你的网络回调就无法收到!!同理,所有的performAfterDelay之类的api以及NSTimer的在线程中工作都不正常!

那么,该如何让他正常工作呢?很简单,做完事情之前,让线程不要结束,保持空转状态就行了。

- (void)threadFunc

{

NSAutoReleasePool *pool = [NSAutoReleasePool new];

//do something

……



//send your request

[NSURLConnection connectionWithRequest:xxx];

//do some other thing

……

/**

此时线程不结束,等待网络数据的返回

*/

while(shouldExit)

{

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

}

[pool release];

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: