初探在多線程中不執(zhí)行Delegate方法

初次使用案例

如果有人沒有碰到類似問題,可以嘗試看看。

    dispatch_queue_t queue =    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSString *urlString =@"http://dlsw.baidu.com/sw-search-sp/soft/9d/25765/sogou_mac_32c_V3.2.0.1437101586.dmg";
        NSString *encodeURLString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:encodeURLString];
        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
        self.connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
        });

代碼很簡答,就是使用NSURLConnection下載一個dmg格式的大文件。不一樣的是這次我們還順帶使用到了GCD。
若看官們還不了解GCD,簡書好多大神都寫過相關(guān)介紹GCD的文章。
下面繼續(xù)貼出關(guān)于NSURLConnection的delegate方法。

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}

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

好了,萬事具備,讓我們愉快地在delegate方法中下一個斷點來運行。
很快我們就會發(fā)現(xiàn)這根本不會調(diào)用代理方法。

開始思考

其實思考的方向也很明確,既然是線程系的鈴,我們不妨用其來解。
我也就不賣關(guān)子,原因其實就是:線程在delegate方法回調(diào)之前就已經(jīng)提前結(jié)束了。
如果這原因讓你傻眼了,別急,我來用一個簡單的例子來說明。

- (void)viewDidLoad {
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(methodOne) object:nil];
    [thread start];
    [self performSelector:@selector(methodTwo) onThread:thread withObject:nil waitUntilDone:NO];
    NSLog(@"開始");
}

- (void)methodOne {
    NSLog(@"HI~");
}

- (void)methodTwo {
    NSLog(@"Hello~");
}

Run!!!告訴你結(jié)果:
2015-10-19 17:44:36.469 Collection[5597:373711] HI~
2015-10-19 17:44:36.469 Collection[5597:373446] 開始

像這類問題就是因為導(dǎo)致了線程在執(zhí)行結(jié)束后銷毀。因此沒法快樂地說Hello~

而這其中還涉及到一個東西:RunLoop。
這里也不過多介紹,稍微簡單地科普一下:

此處輸入圖片的描述
此處輸入圖片的描述
  1. 主線程默然是啟動RunLoop的。
  2. 子線程剛創(chuàng)建的時候沒有RunLoop,需要自己手動去添加。
  3. 主線程會在app結(jié)束后銷毀RunLoop。子線程結(jié)束后銷毀RunLoop。

說到這里也順帶說一下,我們廣泛使用的AFNetWorking,這個第三方網(wǎng)絡(luò)請求框架會開啟一個新線程來添加自己runloop事件。
無論使用NSOperation+NSURLConnection并發(fā)模型或者&GCD的并發(fā)模型,NSURLConnection遇到的這種無法回調(diào)的問題。
AFNetWorking是這樣解決的,單獨建立起一個global thread,內(nèi)置runLoop,所有的connection都由這個runloop發(fā)起,回調(diào)也是它接收,不占用主線程,也不耗CPU資源。

 + (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;
}

動手解決

既然不想讓線程提前結(jié)束,通常我們會用以下方式來解決。

  1. 創(chuàng)建NSTimer,掛載事件源,強行不讓線程提前結(jié)束,當(dāng)然這種方法太Low,我選擇無視。
  2. 向創(chuàng)建的RunLoop添加NSPort,讓線程不會自己停下,然后添加判斷,來推出循環(huán)。
    不多說,上代碼。
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
   
   dispatch_async(queue, ^{
       NSString *urlString =@"http://dlsw.baidu.com/sw-search-sp/soft/9d/25765/sogou_mac_32c_V3.2.0.1437101586.dmg";
       NSString *encodeURLString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
       NSURL *url = [NSURL URLWithString:encodeURLString];
       NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
       self.connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
       if (self.connection) {
           NSPort* port = [NSPort port];
           NSRunLoop* rl = [NSRunLoop currentRunLoop]; // Get the runloop
           [rl addPort:port forMode:NSDefaultRunLoopMode];
           [self.connection scheduleInRunLoop:rl forMode:NSDefaultRunLoopMode];
       }
       
       while(!_isFinished) {
           [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
       }
       
   });

由于本文介紹到了線程和RunLoop這兩個開發(fā)大家樂于討論的概念
大家就自行查閱啦~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載:http://www.cocoachina.com/ios/20150601/11970.html RunL...
    Gatling閱讀 1,458評論 0 13
  • RunLoop的概念 一般來講,一個線程一次只能執(zhí)行一個任務(wù),執(zhí)行完成后線程就會退出。如果我們需要一個機制,讓線程...
    IOS學(xué)渣閱讀 467評論 1 4
  • http://www.cocoachina.com/ios/20150601/11970.html RunLoop...
    紫色冰雨閱讀 860評論 0 3
  • 原文地址:http://blog.ibireme.com/2015/05/18/runloop/ RunLoop ...
    大餅炒雞蛋閱讀 1,177評論 0 6
  • ——阿基米德說,給我一個支點 我可以撬動地球” 在一個暖暖的午后的陽臺上 不需要太多的語言 一杯玫瑰花...
    gezhe1967閱讀 164評論 0 3