我有一个操作“A”,它使用异步 NSURLConnection 从 Web 服务中检索 ID 列表。当收到响应时,操作会遍历这些 ID,并为每个 ID 创建一个操作“B”并将它们添加到队列中。
当我开始将 maxConcurrentOperationCount 设置为 1 进行测试时,我无法执行超过 A 操作。所以看起来加入队列的“B”操作仍在等待“A”完成。
“executing”和“finished”属性已正确更新,“isFinished”上的 KVO 通知按预期工作,但队列仍包含 2 个操作,“A”操作从未删除。
我尝试通过“performSelectorOnMainThreadselector(start)”更改在 NSRunLoop 中使用端口调度连接的代码,它解决了这个问题,但它创建了另一个问题。执行操作“B”时,根据服务器响应,他们可以通过调用其“start”方法而不是将它们添加到队列中来启动其他非并发操作“C”,在这种情况下,我需要“B”直到“C”完成才完成(这就是为什么我使用“start”而不是将“C”添加到队列中),并且我不想在主线程上执行“C”,这就是正在发生的事情当我使用“performSelectorOnMainThread”时。
如果有人可以帮助我解决 runloop 代码的问题,我尝试查看 AFNetworking 和其他库,但我看不出我做错了什么。
- (void)send
{
serverConnection = [[NSURLConnection alloc] initWithRequest: urlRequest delegate: self startImmediately: NO];
port = [NSPort port];
runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort: port forMode: NSDefaultRunLoopMode];
[serverConnection scheduleInRunLoop: runLoop forMode: NSDefaultRunLoopMode];
[serverConnection start];
[runLoop run];
}
- (void)connectionNSURLConnection *)theConnection didFailWithErrorNSError *)theError
{
[runLoop removePort: port forMode: NSRunLoopCommonModes];
// code handling error
}
- (void)connectionDidFinishLoadingNSURLConnection *)theConnection
{
[runLoop removePort: port forMode: NSRunLoopCommonModes];
// code processing response
// If this is executed on main thread, non-concurrent operations created and started from the response processing code,
// will be executed on main thread, instead of using the thread that was dedicated to this operation.
}
Best Answer-推荐答案 strong>
根据NSRunLoop 方法run 的文档:
Manually removing all known input sources and timers from the run loop is not a guarantee that the run loop will exit. OS X can install and remove additional input sources as needed to process requests targeted at the receiver’s thread. Those sources could therefore prevent the run loop from exiting.
If you want the run loop to terminate, you shouldn't use this method. Instead, use one of the other run methods and also check other arbitrary conditions of your own, in a loop. A simple example would be:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
where shouldKeepRunning is set to NO somewhere else in the program.
显然,您可以使用 ![self isFinished] 而不是使用 shouldKeepRunning ,但这说明了这一点。
如果您要启用多个并发操作(并且为了有效地运行所有 B 请求,您应该认真考虑这一点),您可能想看看 AFNetworking 做了什么,它是(a )为网络请求创建一个专用线程并在那里启动运行循环,(b)在此运行循环上安排所有网络请求; (c) 使操作并发(例如 isConcurrent 返回 YES )。
关于ios - NSOperation 和 NSURLConnection,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/22766564/
|