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 - <NSURLConnectionDataDelegate>
- (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 - <NSURLConnectionDataDelegate>
- (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 - <NSURLConnectionDataDelegate>
- (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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章