iOS,NSURLConnection:在不同线程上委托回调?

时间:2011-11-22 02:15:10

标签: ios nsurlconnection nsrunloop

如何让NSURLConnection从不同的线程而不是主线程调用它的委托方法。我正在尝试使用scheduleInRunLoop:forMode:但似乎没有做我想要的。

我必须下载一个大文件,它会频繁地中断主线程,以至于正在发生的一些渲染开始变得不稳定。

NSURLRequest * request = [NSURLRequest requestWithURL:url];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
NSRunLoop * loop = [NSRunLoop currentRunLoop];
NSLog(@"loop mode: %@",[loop currentMode]);
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];

我没有看到的另一件事是“模式”只记录了两种模式,所以没有多少真正要测试。

有什么想法吗?

由于

4 个答案:

答案 0 :(得分:6)

有几种选择:

  1. 在执行委托方法时,请使用dispatch_async
  2. 在后台线程上开始计划连接。
  3. 你可以这样做:

    // all the setup comes here
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSRunLoop *loop = [NSRunLoop currentRunLoop];
        [connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes];
        [loop run]; // make sure that you have a running run-loop.
    });
    

    如果您想要保证正在运行的线程,请适当地将呼叫替换为dispatch_get_global_queue()

答案 1 :(得分:2)

如果你想在一个单独的线程上执行下载,我很确定这些是你正在寻找的机器人......

- (void) dispatchRequest{
    self->finished = NO;
    NSMutableURLRequest* request = //Formulate your request
    NSThread* download_thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadThreadLoop:) object:request];
    [download_thread start];
}
- (void) downloadThreadLoop:(NSMutableURLRequest*) request{

    NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

    while(!self->finished]){
        //This line below is the magic!
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
}

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

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

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    //...   
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
    //...   
    self->finished = YES;
}

答案 2 :(得分:0)

如果您真的需要在新线程中进行下载,detachNewThreadSelector:toTarget:withObject:,设置(和销毁)NSAutoreleasePool可能更容易,然后使用其中一个同步选择器,如{{} 1}} NSData。这不会使用异步dataWithContentsOfURL:

因为这个调用是同步的,所以在下载文件之前它不会返回,这会阻塞主线程,但是因为你在一个新线程中,它不会。请注意,这通常是不鼓励的行为。主线程中是否还有其他可以优化的代码?

答案 3 :(得分:0)

NSURLConnection已经异步下载主线程。如果我理解你的问题,你希望委托消息在主线程以外的线程上发送?您不能这样做,因为您无法修改NSURLConnection的内部实现。我可以想出两种模拟方法。

  1. 创建NSURLConnection(例如MyURLConnection)的sublcass,将自己指定为自己的委托。请注意,这会产生有意的保留周期,因此请小心。 MyURLConnection应定义支持delegate的新NSURLConnectionDelegate。我们称之为finalDelegate。当MyURLConnection处理它自己的委托消息时,在你想要的任何线程上将它们转发或发送到finalDelegate

  2. 与选项#1类似但没有子类。处理主线程上的NSURLConnection委托方法,并将它们转发/发送到您喜欢的任何线程。

  3. 主要区别在于,如果您希望可重用的子类以这种方式运行,或者它是一次性实现。

    编辑:添加了有关如何在后台运行代码的建议

    如果你要在后台处理响应,我会使用操作或大中央调度。无需乱跑循环和创建线程。查看Apple的Concurrency Programming Guide