初次使用案例
如果有人沒(méi)有碰到類似問(wè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];
});
代碼很簡(jiǎn)答,就是使用NSURLConnection下載一個(gè)dmg格式的大文件吐根。不一樣的是這次我們還順帶使用到了GCD赔蒲。
若看官們還不了解GCD,簡(jiǎn)書(shū)好多大神都寫(xiě)過(guò)相關(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
{
}
好了愧口,萬(wàn)事具備,讓我們愉快地在delegate方法中下一個(gè)斷點(diǎn)來(lái)運(yùn)行类茂。
很快我們就會(huì)發(fā)現(xiàn)這根本不會(huì)調(diào)用代理方法耍属。
開(kāi)始思考
其實(shí)思考的方向也很明確,既然是線程系的鈴,我們不妨用其來(lái)解。
我也就不賣(mài)關(guān)子巩检,原因其實(shí)就是:線程在delegate方法回調(diào)之前就已經(jīng)提前結(jié)束了厚骗。
如果這原因讓你傻眼了,別急,我來(lái)用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明。
- (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(@"開(kāi)始");
}
- (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] 開(kāi)始
像這類問(wèn)題就是因?yàn)閷?dǎo)致了線程在執(zhí)行結(jié)束后銷毀兢哭。因此沒(méi)法快樂(lè)地說(shuō)Hello~
而這其中還涉及到一個(gè)東西:RunLoop领舰。
這里也不過(guò)多介紹,稍微簡(jiǎn)單地科普一下:
![此處輸入圖片的描述](https://developer.apple.com/library/prerelease/mac/documentation/Cocoa/Conceptual/Multithreading/Art/runloop.jpg)
- 主線程默然是啟動(dòng)RunLoop的迟螺。
- 子線程剛創(chuàng)建的時(shí)候沒(méi)有RunLoop,需要自己手動(dòng)去添加冲秽。
- 主線程會(huì)在app結(jié)束后銷毀RunLoop。子線程結(jié)束后銷毀RunLoop矩父。
說(shuō)到這里也順帶說(shuō)一下,我們廣泛使用的AFNetWorking,這個(gè)第三方網(wǎng)絡(luò)請(qǐng)求框架會(huì)開(kāi)啟一個(gè)新線程來(lái)添加自己runloop事件锉桑。
無(wú)論使用NSOperation+NSURLConnection并發(fā)模型或者&GCD的并發(fā)模型,NSURLConnection遇到的這種無(wú)法回調(diào)的問(wèn)題。
AFNetWorking是這樣解決的窍株,單獨(dú)建立起一個(gè)global thread,內(nèi)置runLoop,所有的connection都由這個(gè)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;
}
動(dòng)手解決
既然不想讓線程提前結(jié)束,通常我們會(huì)用以下方式來(lái)解決。
- 創(chuàng)建NSTimer,掛載事件源,強(qiáng)行不讓線程提前結(jié)束辙售,當(dāng)然這種方法太Low,我選擇無(wú)視轻抱。
- 向創(chuàng)建的RunLoop添加NSPort,讓線程不會(huì)自己停下,然后添加判斷,來(lái)推出循環(huán)。
不多說(shuō),上代碼旦部。
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這兩個(gè)開(kāi)發(fā)大家樂(lè)于討論的概念
大家就自行查閱啦~~