Lor*_*o B 3 asynchronous objective-c nsoperation nsoperationqueue ios
这是一个两部分问题.希望有人可以回答完整的答案.
NSOperations是强大的对象.它们可以是两种不同的类型:非并发或并发.
第一种类型同步运行.您可以通过将非并发操作添加到a中来利用它们NSOperationQueue.后者为您创建一个线程.结果包括以并发方式运行该操作.唯一需要注意的是这种操作的生命周期.当其main方法完成时,它将从队列中删除.处理异步API时,这可能是一个问题.
现在,并发操作呢?来自Apple doc
如果要实现并发操作(即,相对于调用线程异步运行的操作),则必须编写其他代码以异步启动操作.例如,您可能会生成一个单独的线程,调用异步系统函数或执行任何其他操作以确保start方法启动任务并立即返回,并且很可能在任务完成之前返回.
这对我来说几乎是清楚的.它们以异步方式运行.但是你必须采取适当的行动来确保他们这样做.
我不清楚的是以下内容.Doc说:
注意:在OS X v10.6中,操作队列忽略isConcurrent返回的值,并始终从单独的线程调用操作的start方法.
它的真正含义是什么?如果我在一个并发操作中会发生NSOperationQueue什么?
然后,在此并发操作中,并发操作用于通过NSURLConnection(以其异步形式)下载某些HTTP内容.操作是并发的并包含在特定队列中.
UrlDownloaderOperation * operation = [UrlDownloaderOperation urlDownloaderWithUrlString:url];
[_queue addOperation:operation];
Run Code Online (Sandbox Code Playgroud)
由于NSURLConnection需要循环运行,作者start在主线程中分流方法(所以我想将操作添加到它产生不同的队列的队列中).以这种方式,主运行循环可以调用操作中包含的委托.
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
return;
}
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
NSURLRequest * request = [NSURLRequest requestWithURL:_url];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
}
- (BOOL)isConcurrent
{
return YES;
}
// delegate method here...
Run Code Online (Sandbox Code Playgroud)
我的问题如下.这个线程安全吗?运行循环侦听源,但在后台线程中调用调用的方法.我错了吗?
编辑
我根据Dave Dribin提供的代码自己完成了一些测试(见1).正如你所写的那样,我注意到NSURLConnection在主线程中调用了回调函数.
好的,但现在我仍然很困惑.我会试着解释一下我的怀疑.
为什么在并发操作中包含在主线程中调用其回调的异步模式?将start方法分流到主线程允许在主线程中执行回调,以及队列和操作如何?我在哪里利用GCD提供的线程机制?
希望这很清楚.
这是一个很长的答案,但简短的版本是你正在做的事情是完全正确和线程安全,因为你已经迫使操作的重要部分在主线程上运行.
你的第一个问题是,"如果我在NSOperationQueue中添加并发操作会怎么样?" 从iOS 4开始,NSOperationQueue在幕后使用GCD.当您的操作到达队列的顶部时,它将被提交给GCD,GCD管理一个私有线程池,根据需要动态增长和收缩.GCD分配其中一个线程来运行start你的操作方法,并保证这个线程永远不会是主线程.
当start方法在并发操作中完成时,没有什么特别的事情发生(这是重点).该队列将允许您的操作永远运行,直到您设置isFinished为YES并执行正确的KVO willChange/didChange调用,而不管调用线程如何.通常你会创建一个调用finish它的方法,它看起来像你一样.
所有这一切都很好,但如果您需要观察或操纵运行操作的线程,则需要注意一些事项.要记住的重要一点是:不要乱用GCD管理的线程.你不能保证它们会超过当前的执行帧,你绝对不能保证后续的委托调用(即,from NSURLConnection)将在同一个线程上发生.事实上,他们可能不会.
在您的代码示例中,您已经分流start到主线程,因此您不必担心后台线程(GCD或其他).当你创建NSURLConnection它时,它会在当前的运行循环中被调度,并且它的所有委托方法将在该运行循环的线程上被调用,这意味着在主线程上启动连接可以保证其委托回调也发生在主线程上.从这个意义上来说,它是"线程安全的",因为除了操作本身的开始之外,几乎没有任何事实发生在后台线程上,这实际上可能是一个优势,因为GCD可以立即回收线程并将其用于其他事情.
让我们想象如果你没有强制start在主线程上运行并且只是使用了GCD给你的线程会发生什么.如果它的线程消失,运行循环可能会永远挂起,例如当它被GCD回收到其私有池中时.有一些技术可以保持线程保持活动状态(例如添加空NSPort),但它们不适用于由GCD创建的线程,只适用于您自己创建的线程,并且可以保证线程的生命周期.
这里的危险是,在轻负载下,你实际上可以在GCD线程上运行一个运行循环,并认为一切都很好.一旦你开始运行许多并行操作,特别是如果你需要在中途取消它们,你将开始看到从未完成的操作,永远不会释放,泄漏内存.如果你想要完全安全,你需要创建自己的专用NSThread并保持运行循环永远.
在现实世界中,执行您正在执行的操作并在主线程上运行连接要容易得多.管理连接消耗的CPU非常少,并且在大多数情况下不会干扰您的UI,因此在后台完全运行连接几乎没有什么好处.主线程的运行循环始终在运行,您不需要乱用它.
但是,可以NSURLConnection使用上述专用线程方法完全在后台运行连接.例如,查看JXHTTP,特别是类JXOperation和JXURLConnectionOperation
| 归档时间: |
|
| 查看次数: |
1749 次 |
| 最近记录: |