NSConnection和RunLoop的关系

#import "ViewController.h"
@interface ViewController () <NSURLConnectionDataDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"]] delegate:self];
    // 决定代理方法在哪个队列中执行(在子线程中执行)
        [conn setDelegateQueue:[[NSOperationQueue alloc] init]];
}

#pragma mark - 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"didReceiveResponse----%@", [NSThread currentThread]);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{

    NSLog(@"didReceiveData----%@", [NSThread currentThread]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSLog(@"connectionDidFinishLoading----%@", [NSThread currentThread]);
}

@end

上面这段程序是在主线程中创建NSURLConnection ,给服务器发送请求,程序可以成功的接受到服务器返回的数据
但是一但将请求放在子线程中发送,就不能接受到服务器返回的数据了。情况如下面代码所示:

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"]] delegate:self];
        // 决定代理方法在哪个队列中执行(在子线程中执行)
        [conn setDelegateQueue:[[NSOperationQueue alloc] init]];
    });
}

这是为什么呢,原因如下:

  • 因为NSURLConnectionRunLoop有关系
  • NSURLConnection发出请求,等待接收服务器一点一点返回的数据,需要有一个运行循环等待服务器给NSURLConnection数据,也就是说NSURLConnection是在RunLoop中接收服务器返回的数据
  • NSURLConnection内部会关联当前线程对应的RunLoop,不断的给当前线程的RunLoop传递消息,RunLoop接收到Source进行处理
  • NSURLConnection在子线程发送请求时,子线程的RunLoop默认是不启动的,所以接受不到服务器返回的数据。在主线程中,主线程的RunLoop是默认启动的,所以可以接受服务器返回的数据
  • 要想NSURLConnection在子线程发送请求,可以接收到服务器返回的数据,要开启子线程的RunLoop,具体方法如下,有两种方法实现:
    • 方法一:
#import "ViewController.h"
@interface ViewController () <NSURLConnectionDataDelegate>
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"]] delegate:self];
        // 决定代理方法在哪个队列中执行
        [conn setDelegateQueue:[[NSOperationQueue alloc] init]];

        // 启动子线程的runLoop
        [[NSRunLoop currentRunLoop] run];
    });
}

#pragma mark - 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"didReceiveResponse----%@", [NSThread currentThread]);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{

    NSLog(@"didReceiveData----%@", [NSThread currentThread]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSLog(@"connectionDidFinishLoading----%@", [NSThread currentThread]);
}
@end
  • 方法二:
#import "ViewController.h"
@interface ViewController () <NSURLConnectionDataDelegate>
/** runLoop */
@property (nonatomic, assign) CFRunLoopRef runLoop;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"]] delegate:self];
        // 决定代理方法在哪个队列中执行
        [conn setDelegateQueue:[[NSOperationQueue alloc] init]];

        // 启动子线程的runLoop
        self.runLoop = CFRunLoopGetCurrent();

        // 启动runLoop
        CFRunLoopRun();
    });
}

#pragma mark - 
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    NSLog(@"didReceiveResponse----%@", [NSThread currentThread]);
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{

    NSLog(@"didReceiveData----%@", [NSThread currentThread]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSLog(@"connectionDidFinishLoading----%@", [NSThread currentThread]);

    // 一般来说RunLoop会自己停止,然是如果RunLoop没有自动停止,我们可以手动停止
    // CFRunLoopStop(self.runLoop);
}
@end

你可能感兴趣的:(多线程,网络)