AFNetworking - 为什么会产生网络请求线程?

时间:2021-10-19 00:36:40

I'm trying to understand Operations and Threads better, and looked to AFNetworking's AFURLConnectionOperation subclass for example, real-world, source code.

我试图更好地理解操作和线程,并查看AFNetworking的AFURLConnectionOperation子类,例如,真实世界的源代码。

My current understanding is when instances of NSOperation are added to an operation queue, the queue, among other things, manages the thread responsible for executing the operation. In Apple's documentation of NSOperation it points out that even if subclasses return YES for -isConcurrent the operation will always be started on a separate thread (as of 10.6).

我目前的理解是当NSOperation的实例被添加到操作队列时,该队列除其他外,管理负责执行操作的线程。在Apple的NSOperation文档中,它指出即使子类为-isConcurrent返回YES,操作也将始终在一个单独的线程上启动(截至10.6)。

Based on Apple's strong language throughout the Thread Programming Guide and Concurrency Programming Guide, it seems like managing a thread is best left up to the internal implementation of NSOperationQueue.

基于Apple在线程编程指南和并发编程指南中强大的语言,管理线程似乎最好留给NSOperationQueue的内部实现。

However, AFNetworking's AFURLConnectionOperation subclass spawns a new NSThread, and the execution of the operation's -main method is pushed off onto this network request thread. Why? Why is this network request thread necessary? Is this a defensive programming technique because the library is designed to be used by a wide audience? Is it just less hassle for consumers of the library to debug? Is there a (subtle) performance benefit to having all networking activity on a dedicated thread?

但是,AFNetworking的AFURLConnectionOperation子类会生成一个新的NSThread,并且操作的-main方法的执行被推送到此网络请求线程中。为什么?为什么这个网络请求线程是必要的?这是一种防御性编程技术,因为该库旨在供广大读者使用吗?对于库的消费者来说,调试是否更少麻烦?在专用线程上进行所有网络活动是否有(微妙的)性能优势?

(Added Jan 26th)
In a blog post by Dave Dribin, he illustrates how to move an operation back onto the main thread using the specific example of NSURLConnection.

(在1月26日添加)在Dave Dribin的博客文章中,他演示了如何使用NSURLConnection的具体示例将操作移回主线程。

My curiosity comes from the following section in Apple's Thread Programming Guide:

我的好奇心来自Apple的线程编程指南中的以下部分:

Keep Your Threads Reasonably Busy.
If you decide to create and manage threads manually, remember that threads consume precious system resources. You should do your best to make sure that any tasks you assign to threads are reasonably long-lived and productive. At the same time, you should not be afraid to terminate threads that are spending most of their time idle. Threads use a nontrivial amount of memory, some of it wired, so releasing an idle thread not only helps reduce your application’s memory footprint, it also frees up more physical memory for other system processes to use.

保持你的线程合理繁忙。如果您决定手动创建和管理线程,请记住线程占用宝贵的系统资源。您应该尽力确保分配给线程的任何任务都是合理的长寿和高效的。与此同时,您不应该害怕终止花费大部分时间闲置的线程。线程使用大量内存,其中一些是有线的,因此释放空闲线程不仅有助于减少应用程序的内存占用,还可以释放更多物理内存供其他系统进程使用。

It seems to me that AFNetworking's network request thread isn't being "kept reasonably busy;" it's running an infinite while-loop for handling networking I/O. But, see, that's the point of this questions - I don't know and I am only guessing.

在我看来,AFNetworking的网络请求线程并没有“保持相当繁忙”;它正在运行一个无限的while循环来处理网络I / O.但是,看,这就是问题的关键 - 我不知道,我只是在猜测。

Any insight or deconstruction of AFURLConnectionOperation with specific regards to operations, threads (run loops?), and / or GCD would be highly beneficial to filling in the gaps of my understanding.

AFURLConnectionOperation对操作,线程(运行循环?)和/或GCD的特定关注的任何洞察或解构都将非常有利于填补我理解的空白。

1 个解决方案

#1


6  

Its an interesting question and the answer is all about the semantics of how NSOperation and NSURLConnection interact and work together.

这是一个有趣的问题,答案是关于NSOperation和NSURLConnection如何相互作用和协同工作的语义。

An NSURLConnection is itself an asynchronous task. It all happens in the background and calls its delegate periodically with the results. When you start an NSURLConnection it schedules the delegate callbacks using the runloop it is scheduled on, so a runloop must always be running on the thread you are executing an NSURLConnection on.

NSURLConnection本身就是一个异步任务。这一切都发生在后台,并定期调用其委托结果。当您启动NSURLConnection时,它会使用调度的runloop来调度委托回调,因此必须始终在正在执行NSURLConnection的线程上运行runloop。

Therefore the method -start on our AFURLConnectionOperation will always have to return before the operation finishes so it can receive the callbacks. This requires that AFURLConnectionOperation be an asynchronous operation.

因此,AFURLConnectionOperation上的方法-start将始终必须在操作完成之前返回,以便它可以接收回调。这要求AFURLConnectionOperation是一个异步操作。

from: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/index.html

The value of property is YES for operations that run asynchronously with respect to the current thread or NO for operations that run synchronously on the current thread. The default value of this property is NO.

对于与当前线程异步运行的操作,属性值为YES,对于在当前线程上同步运行的操作,属性值为NO。此属性的默认值为NO。

But AFURLConnectionOperation overrides this method and returns YES as we would expect. Then we see from the class description:

但AFURLConnectionOperation会覆盖此方法并返回YES,正如我们所期望的那样。然后我们从类描述中看到:

When you call the start method of an asynchronous operation, that method may return before the corresponding task is completed. An asynchronous operation object is responsible for scheduling its task on a separate thread. The operation could do that by starting a new thread directly, by calling an asynchronous method, or by submitting a block to a dispatch queue for execution. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.

当您调用异步操作的start方法时,该方法可能会在相应的任务完成之前返回。异步操作对象负责在单独的线程上调度其任务。该操作可以通过直接启动新线程,通过调用异步方法,或者通过将块提交到调度队列来执行来实现。当控制权返回给调用者时,操作是否正在进行实际上并不重要,只是它可能正在进行中。

AFNetworking creates a single network thread using a class method that it schedules all the NSURLConnection objects (and their resulting delegate callbacks) on. Here is that code from AFURLConnectionOperation

AFNetworking使用类方法创建单个网络线程,该方法调度所有NSURLConnection对象(及其生成的委托回调)。这是来自AFURLConnectionOperation的代码

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });

    return _networkRequestThread;
}

Here is code from AFURLConnectionOperation showing them scheduling the NSURLConnection on the runloop of the AFNetwokring thread in all runloop modes

以下是来自AFURLConnectionOperation的代码,显示他们在所有runloop模式下在AFNetwokring线程的runloop上安排NSURLConnection

- (void)start {
    [self.lock lock];
    if ([self isCancelled]) {
        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    } else if ([self isReady]) {
        self.state = AFOperationExecutingState;

        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    }
    [self.lock unlock];
}

- (void)operationDidStart {
    [self.lock lock];
    if (![self isCancelled]) {
        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        for (NSString *runLoopMode in self.runLoopModes) {
            [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
            [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
        }

        //...
    }
    [self.lock unlock];
}

here [NSRunloop currentRunloop] retrieves the runloop on the AFNetworking thread instead of the mainRunloop as the -operationDidStart method is called from that thread. As a bonus we get to run the outputStream on the background thread's runloop as well.

这里[NSRunloop currentRunloop]检索AFNetworking线程上的runloop而不是mainRunloop,因为从该线程调用了-operationDidStart方法。作为奖励,我们也可以在后台线程的runloop上运行outputStream。

Now AFURLConnectionOperation waits for the NSURLConnection callbacks and updates its own NSOperation state variables (cancelled, finished, executing) itself as the network request progresses. The AFNetworking thread spins its runloop repeatedly so that as NSURLConnections from potentially many AFURLConnectionOperations schedule their callbacks they are called and the AFURLConnectionOperation objects can react to them.

现在AFURLConnectionOperation在网络请求进行时等待NSURLConnection回调并更新自己的NSOperation状态变量(取消,完成,执行)。 AFNetworking线程反复旋转其runloop,以便来自潜在的AFURLConnectionOperations的NSURLConnections可以调度它们的回调,并且AFURLConnectionOperation对象可以对它们做出反应。

If you always plan to use queues to execute your operations, it is simpler to define them as synchronous. If you execute operations manually, though, you might want to define your operation objects as asynchronous. Defining an asynchronous operation requires more work, because you have to monitor the ongoing state of your task and report changes in that state using KVO notifications. But defining asynchronous operations is useful in cases where you want to ensure that a manually executed operation does not block the calling thread.

如果您始终计划使用队列来执行操作,则将它们定义为同步更为简单。但是,如果手动执行操作,则可能需要将操作对象定义为异步操作。定义异步操作需要更多工作,因为您必须监视任务的持续状态并使用KVO通知报告该状态中的更改。但是,如果要确保手动执行的操作不会阻止调用线程,则定义异步操作非常有用。

Also note that you can also use an NSOperation without a NSOperationQueue by calling -start and observing it until -isFinished returns YES. If AFURLConnectionOperation was implemented as a synchronous operation and blocked the current thread waiting for NSURLConnection to finish it would never actually finish as NSURLConnection would schedule its callbacks on the current runloop, which wouldn't be running as we would be blocking it. Therefore to support this valid scenario of using NSOperation we have to make the AFURLConnectionOperation asynchronous.

另请注意,您也可以通过调用-start并观察它来使用没有NSOperationQueue的NSOperation,直到-isFinished返回YES。如果AFURLConnectionOperation是作为同步操作实现的并且阻止当前线程等待NSURLConnection完成它将永远不会实际完成,因为NSURLConnection将在当前runloop上调度其回调,而当前runloop将不会运行,因为我们将阻止它。因此,为了支持使用NSOperation的这种有效场景,我们必须使AFURLConnectionOperation异步。

Answers to Questions

  • Yes, AFNetworking creates one thread which it uses to schedule all connections. Thread creation is expensive. (this is partly why GCD was created. GCD keeps a pool of threads running for you and dispatches blocks on the different threads as needed without having to create, destroy and manage threads yourself)

    是的,AFNetworking创建了一个用于安排所有连接的线程。线程创建很昂贵。 (这也是创建GCD的部分原因.GCD会为您运行一个线程池,并根据需要在不同的线程上调度块,而无需自己创建,销毁和管理线程)

  • The processing is not done on the background AFNetworking thread. AFNetworking uses the completionBlock property of NSOperation to do its processing which is executed when finished is set to YES.

    处理不在后台AFNetworking线程上完成。 AFNetworking使用NSOperation的completionBlock属性进行处理,当finish设置为YES时执行。

The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it. For example, if you have a custom thread for coordinating the completion of the operation, you could use the completion block to ping that thread.

您的完成块的确切执行上下文无法保证,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。相反,您应该将该工作分流到应用程序的主线程或能够执行此操作的特定线程。例如,如果您有一个用于协调操作完成的自定义线程,则可以使用完成块来ping该线程。

the post processing of HTTP connections is handled in AFHTTPRequestOperation. This class creates a dispatch queue specifically for transforming response objects in the background and shunts the work off onto that queue. see here

HTTP连接的后处理在AFHTTPRequestOperation中处理。此类创建一个调度队列,专门用于在后台转换响应对象,并将工作分流到该队列。看这里

- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    self.completionBlock = ^{
        //...
        dispatch_async(http_request_operation_processing_queue(), ^{
            //...

I guess this begs the question could they have written AFURLConnectionOperation to not make a thread. I think the answer is yes as there is this API

我想这可能会引发他们写AFURLConnectionOperation以便不创建线程的问题。我认为答案是肯定的,因为有这个API

- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);

Which is meant to schedule your delegate callbacks on a specific operation queue as opposed to using the runloop. But as we're looking at the legacy part of AFNetworking and that API was only available in iOS 5 and OS X 10.7. Looking at the blame view on Github for AFURLRequestOperation we can see that mattt actually wrote the +networkRequestThread method coincidentally on the actual day the iPhone 4s and iOS 5 were announced back in 2011! As such we can reason that the thread exists because at the time it was written we can see that making a thread and scheduling your connections on it was the only way to receive callbacks from NSURLConnection in the background while running in an asynchronous NSOperation subclass.

这意味着在特定操作队列上安排您的委托回调,而不是使用runloop。但正如我们正在研究AFNetworking的遗留部分那样,API仅适用于iOS 5和OS X 10.7。看看Github对AFURLRequestOperation的责备观点,我们可以看到mattt实际上是在2011年iPhone 4s和iOS 5宣布的实际日期编写了+ networkRequestThread方法!因此我们可以推断该线程是存在的,因为在编写时我们可以看到创建一个线程并在其上调度连接是在异步NSOperation子类中运行时在后台接收来自NSURLConnection的回调的唯一方法。

  • the thread is created using the dispatch_once function. (see the extra code snipped i added as you suggested) This function ensures that the code enclosed in the block it runs will be run only once in the lifetime of the application. The AFNetworking thread is created when it is needed and then persists for the lifetime of the application

    线程是使用dispatch_once函数创建的。 (请参阅我建议添加的额外代码剪切)此函数确保其运行的块中包含的代码在应用程序的生命周期中仅运行一次。 AFNetworking线程在需要时创建,然后在应用程序的生命周期内持续存在

  • When i wrote NSURLConnectionOperation i meant AFURLConnectionOperation. I corrected that thanks for mentioning it :)

    当我写NSURLConnectionOperation时,我的意思是AFURLConnectionOperation。我纠正了,谢谢你提到它:)

#1


6  

Its an interesting question and the answer is all about the semantics of how NSOperation and NSURLConnection interact and work together.

这是一个有趣的问题,答案是关于NSOperation和NSURLConnection如何相互作用和协同工作的语义。

An NSURLConnection is itself an asynchronous task. It all happens in the background and calls its delegate periodically with the results. When you start an NSURLConnection it schedules the delegate callbacks using the runloop it is scheduled on, so a runloop must always be running on the thread you are executing an NSURLConnection on.

NSURLConnection本身就是一个异步任务。这一切都发生在后台,并定期调用其委托结果。当您启动NSURLConnection时,它会使用调度的runloop来调度委托回调,因此必须始终在正在执行NSURLConnection的线程上运行runloop。

Therefore the method -start on our AFURLConnectionOperation will always have to return before the operation finishes so it can receive the callbacks. This requires that AFURLConnectionOperation be an asynchronous operation.

因此,AFURLConnectionOperation上的方法-start将始终必须在操作完成之前返回,以便它可以接收回调。这要求AFURLConnectionOperation是一个异步操作。

from: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/index.html

The value of property is YES for operations that run asynchronously with respect to the current thread or NO for operations that run synchronously on the current thread. The default value of this property is NO.

对于与当前线程异步运行的操作,属性值为YES,对于在当前线程上同步运行的操作,属性值为NO。此属性的默认值为NO。

But AFURLConnectionOperation overrides this method and returns YES as we would expect. Then we see from the class description:

但AFURLConnectionOperation会覆盖此方法并返回YES,正如我们所期望的那样。然后我们从类描述中看到:

When you call the start method of an asynchronous operation, that method may return before the corresponding task is completed. An asynchronous operation object is responsible for scheduling its task on a separate thread. The operation could do that by starting a new thread directly, by calling an asynchronous method, or by submitting a block to a dispatch queue for execution. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.

当您调用异步操作的start方法时,该方法可能会在相应的任务完成之前返回。异步操作对象负责在单独的线程上调度其任务。该操作可以通过直接启动新线程,通过调用异步方法,或者通过将块提交到调度队列来执行来实现。当控制权返回给调用者时,操作是否正在进行实际上并不重要,只是它可能正在进行中。

AFNetworking creates a single network thread using a class method that it schedules all the NSURLConnection objects (and their resulting delegate callbacks) on. Here is that code from AFURLConnectionOperation

AFNetworking使用类方法创建单个网络线程,该方法调度所有NSURLConnection对象(及其生成的委托回调)。这是来自AFURLConnectionOperation的代码

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });

    return _networkRequestThread;
}

Here is code from AFURLConnectionOperation showing them scheduling the NSURLConnection on the runloop of the AFNetwokring thread in all runloop modes

以下是来自AFURLConnectionOperation的代码,显示他们在所有runloop模式下在AFNetwokring线程的runloop上安排NSURLConnection

- (void)start {
    [self.lock lock];
    if ([self isCancelled]) {
        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    } else if ([self isReady]) {
        self.state = AFOperationExecutingState;

        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    }
    [self.lock unlock];
}

- (void)operationDidStart {
    [self.lock lock];
    if (![self isCancelled]) {
        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        for (NSString *runLoopMode in self.runLoopModes) {
            [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
            [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
        }

        //...
    }
    [self.lock unlock];
}

here [NSRunloop currentRunloop] retrieves the runloop on the AFNetworking thread instead of the mainRunloop as the -operationDidStart method is called from that thread. As a bonus we get to run the outputStream on the background thread's runloop as well.

这里[NSRunloop currentRunloop]检索AFNetworking线程上的runloop而不是mainRunloop,因为从该线程调用了-operationDidStart方法。作为奖励,我们也可以在后台线程的runloop上运行outputStream。

Now AFURLConnectionOperation waits for the NSURLConnection callbacks and updates its own NSOperation state variables (cancelled, finished, executing) itself as the network request progresses. The AFNetworking thread spins its runloop repeatedly so that as NSURLConnections from potentially many AFURLConnectionOperations schedule their callbacks they are called and the AFURLConnectionOperation objects can react to them.

现在AFURLConnectionOperation在网络请求进行时等待NSURLConnection回调并更新自己的NSOperation状态变量(取消,完成,执行)。 AFNetworking线程反复旋转其runloop,以便来自潜在的AFURLConnectionOperations的NSURLConnections可以调度它们的回调,并且AFURLConnectionOperation对象可以对它们做出反应。

If you always plan to use queues to execute your operations, it is simpler to define them as synchronous. If you execute operations manually, though, you might want to define your operation objects as asynchronous. Defining an asynchronous operation requires more work, because you have to monitor the ongoing state of your task and report changes in that state using KVO notifications. But defining asynchronous operations is useful in cases where you want to ensure that a manually executed operation does not block the calling thread.

如果您始终计划使用队列来执行操作,则将它们定义为同步更为简单。但是,如果手动执行操作,则可能需要将操作对象定义为异步操作。定义异步操作需要更多工作,因为您必须监视任务的持续状态并使用KVO通知报告该状态中的更改。但是,如果要确保手动执行的操作不会阻止调用线程,则定义异步操作非常有用。

Also note that you can also use an NSOperation without a NSOperationQueue by calling -start and observing it until -isFinished returns YES. If AFURLConnectionOperation was implemented as a synchronous operation and blocked the current thread waiting for NSURLConnection to finish it would never actually finish as NSURLConnection would schedule its callbacks on the current runloop, which wouldn't be running as we would be blocking it. Therefore to support this valid scenario of using NSOperation we have to make the AFURLConnectionOperation asynchronous.

另请注意,您也可以通过调用-start并观察它来使用没有NSOperationQueue的NSOperation,直到-isFinished返回YES。如果AFURLConnectionOperation是作为同步操作实现的并且阻止当前线程等待NSURLConnection完成它将永远不会实际完成,因为NSURLConnection将在当前runloop上调度其回调,而当前runloop将不会运行,因为我们将阻止它。因此,为了支持使用NSOperation的这种有效场景,我们必须使AFURLConnectionOperation异步。

Answers to Questions

  • Yes, AFNetworking creates one thread which it uses to schedule all connections. Thread creation is expensive. (this is partly why GCD was created. GCD keeps a pool of threads running for you and dispatches blocks on the different threads as needed without having to create, destroy and manage threads yourself)

    是的,AFNetworking创建了一个用于安排所有连接的线程。线程创建很昂贵。 (这也是创建GCD的部分原因.GCD会为您运行一个线程池,并根据需要在不同的线程上调度块,而无需自己创建,销毁和管理线程)

  • The processing is not done on the background AFNetworking thread. AFNetworking uses the completionBlock property of NSOperation to do its processing which is executed when finished is set to YES.

    处理不在后台AFNetworking线程上完成。 AFNetworking使用NSOperation的completionBlock属性进行处理,当finish设置为YES时执行。

The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it. For example, if you have a custom thread for coordinating the completion of the operation, you could use the completion block to ping that thread.

您的完成块的确切执行上下文无法保证,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。相反,您应该将该工作分流到应用程序的主线程或能够执行此操作的特定线程。例如,如果您有一个用于协调操作完成的自定义线程,则可以使用完成块来ping该线程。

the post processing of HTTP connections is handled in AFHTTPRequestOperation. This class creates a dispatch queue specifically for transforming response objects in the background and shunts the work off onto that queue. see here

HTTP连接的后处理在AFHTTPRequestOperation中处理。此类创建一个调度队列,专门用于在后台转换响应对象,并将工作分流到该队列。看这里

- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    self.completionBlock = ^{
        //...
        dispatch_async(http_request_operation_processing_queue(), ^{
            //...

I guess this begs the question could they have written AFURLConnectionOperation to not make a thread. I think the answer is yes as there is this API

我想这可能会引发他们写AFURLConnectionOperation以便不创建线程的问题。我认为答案是肯定的,因为有这个API

- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);

Which is meant to schedule your delegate callbacks on a specific operation queue as opposed to using the runloop. But as we're looking at the legacy part of AFNetworking and that API was only available in iOS 5 and OS X 10.7. Looking at the blame view on Github for AFURLRequestOperation we can see that mattt actually wrote the +networkRequestThread method coincidentally on the actual day the iPhone 4s and iOS 5 were announced back in 2011! As such we can reason that the thread exists because at the time it was written we can see that making a thread and scheduling your connections on it was the only way to receive callbacks from NSURLConnection in the background while running in an asynchronous NSOperation subclass.

这意味着在特定操作队列上安排您的委托回调,而不是使用runloop。但正如我们正在研究AFNetworking的遗留部分那样,API仅适用于iOS 5和OS X 10.7。看看Github对AFURLRequestOperation的责备观点,我们可以看到mattt实际上是在2011年iPhone 4s和iOS 5宣布的实际日期编写了+ networkRequestThread方法!因此我们可以推断该线程是存在的,因为在编写时我们可以看到创建一个线程并在其上调度连接是在异步NSOperation子类中运行时在后台接收来自NSURLConnection的回调的唯一方法。

  • the thread is created using the dispatch_once function. (see the extra code snipped i added as you suggested) This function ensures that the code enclosed in the block it runs will be run only once in the lifetime of the application. The AFNetworking thread is created when it is needed and then persists for the lifetime of the application

    线程是使用dispatch_once函数创建的。 (请参阅我建议添加的额外代码剪切)此函数确保其运行的块中包含的代码在应用程序的生命周期中仅运行一次。 AFNetworking线程在需要时创建,然后在应用程序的生命周期内持续存在

  • When i wrote NSURLConnectionOperation i meant AFURLConnectionOperation. I corrected that thanks for mentioning it :)

    当我写NSURLConnectionOperation时,我的意思是AFURLConnectionOperation。我纠正了,谢谢你提到它:)