8

如何让 NSURLConnection 从不同的线程而不是主线程调用它的委托方法。我试图弄乱 scheduleInRunLoop:forMode:but 似乎没有做我想做的事。

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

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

4 回答 4

6

有几种选择:

  1. 在您的委托方法的实现中,使用dispatch_async.
  2. 在后台线程上启动计划连接。

你可以这样做后者:

// 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()适当地替换对的调用。

于 2011-12-26T15:34:01.827 回答
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;
}
于 2012-06-25T16:17:47.303 回答
0

如果您确实需要在新线程中进行下载,则可能更容易detachNewThreadSelector:toTarget:withObject:设置(和销毁) an NSAutoreleasePool,然后使用同步选择器之一,例如NSData's dataWithContentsOfURL:。这不会利用异步NSURLConnectionDelegate

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

于 2011-11-22T02:34:33.130 回答
0

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

  1. 创建一个NSURLConnection(例如MyURLConnection)的子类,将自己指定为自己的委托。请注意,这会创建一个有意的保留周期,所以要小心。MyURLConnection应该定义一个delegate支持NSURLConnectionDelegate. 让我们称之为finalDelegate. 当MyURLConnection处理它自己的委托消息时,将它们转发或分派到finalDelegate您喜欢的任何线程上。

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

主要区别在于您是否想要一个以这种方式运行的可重用子类,或者它是一次性实现。

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

如果您要在后台处理响应,我会使用操作或大型中央调度。无需搞乱运行循环和创建线程。查看 Apple 的并发编程指南

于 2011-11-22T04:09:15.050 回答