如何使用sendAsynchronousRequest:queue:completionHandler:


74

两部分问题

第一部分: 我正在尝试向数据库创建一个ASynchronous请求。我目前正在同步进行操作,但是我想学习两种方法以更好地了解发生的情况。

目前,我已经像这样设置了我的同步呼叫。

- (IBAction)setRequestString:(NSString *)string
{
    //Set database address
    NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:@"http://127.0.0.1:8778/instacodeData/"]; // imac development

    //PHP file name is being set from the parent view
    [databaseURL appendString:string];

    //call ASIHTTP delegates (Used to connect to database)
    NSURL *url = [NSURL URLWithString:databaseURL];

    //SynchronousRequest to grab the data
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSError *error;
    NSURLResponse *response;

    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (!result) {
        //Display error message here
        NSLog(@"Error");
    } else {

        //TODO: set up stuff that needs to work on the data here.
        NSString* newStr = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
        NSLog(@"%@", newStr);
    }
}

我认为我需要做的是替换通话

NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

与异步版本

sendAsynchronousRequest:queue:completionHandler:

但是我不确定传递给queue或completionHandler的内容...任何示例/解决方案将不胜感激。

第二部分: 我一直在阅读有关多任务的内容,我想通过确保在发生中断时我的连接请求完成来支持它。我一直在关注这个例子

它解释了如果发生中断,如何获得更多的时间,我了解它在做什么。如果您有任何示例/教程可以帮助我弄清楚如何应用它,那就太好了!

Answers:


113

第1部分:

NSURL *url = [NSURL URLWithString:urlString];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
    if ([data length] > 0 && error == nil)
        [delegate receivedData:data];
    else if ([data length] == 0 && error == nil)
        [delegate emptyReply];
    else if (error != nil && error.code == ERROR_CODE_TIMEOUT)
        [delegate timedOut];
    else if (error != nil)
        [delegate downloadError:error];
}];

代表调用..我应该在头文件中包括什么代表?
C.Johns

您应该将其委派给自己
mbh 2012年

2
这些方法在您的课程中。您可以根据需要重命名这些方法。还是没有它们。但是将代码放在if then else本身中。或者您可以这样调用[self receiveData:data];
mbh 2012年

12
相信NSURLErrorTimedOut是被接受的价值了ERROR_CODE_TIMEOUT
乔·马西洛蒂

2
注意:sendAsynchronousRequest:urlRequest queue:queue completionHandler:iOS 9中已弃用
理查德(Richard)

38

这是一个示例:

NSString *urlAsString = @"http://www.cnn.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];


[NSURLConnection
         sendAsynchronousRequest:urlRequest
         queue:[[NSOperationQueue alloc] init]
         completionHandler:^(NSURLResponse *response,
                             NSData *data,
                             NSError *error) 
        {

         if ([data length] >0 && error == nil)
         {

                        // DO YOUR WORK HERE

         }
         else if ([data length] == 0 && error == nil)
         {
             NSLog(@"Nothing was downloaded.");
         }
         else if (error != nil){
             NSLog(@"Error = %@", error);
         }

     }];

1
您是否泄漏NSOperationQueue对象?看起来像。还是您只使用ARC而没有提到它?
卢卡斯·彼得

3
我正在使用ARC,只是没有提及。谢谢你的问题!
跳蚤2012年

“ sendAsynchronousRequest:request”行应该是“ sendAsynchronousRequest:urlRequest”吗?
米克,

@Flea请在这里查看我的相关问题。stackoverflow.com/questions/24857919/…–
泰勒·帕夫

25

对于队列参数,请尝试以下魔术:

[NSOperationQueue mainQueue]

如果您在请求完成时更新UI,这将非常有用,因为主队列是主线程。本质上,它为您提供了NSURLConnection的先前行为。但是,如果您打算写入文件或解压缩,则可以在后台队列中完成,然后将异步分派回主队列以进行UI更新。


1
@MaciejSwic否,如文档所述:“队列:当请求完成或失败时,将处理程序块调度到的操作队列。” 因此,是在主线程上运行的完成处理程序,这取决于您想在其中执行的操作可能是好事,也可能不是好事。
算法和布鲁斯

好吧,如果您要更新UI,这就是您想要的。如果没有必要,则没有必要在后台线程上增加运行委托的复杂性。使用主队列的行为与旧的NSURLConnection相同,这在大多数情况下应该没问题。
malhal 2016年

9

我一直在研究类似的问题,我在此发布了该问题并在此处得到了明确的答案,希望对第二部分有所帮助。

对于第1部分,这里提到的其他内容还不错,但是您需要添加另一张支票(我在下面修改了答案)。您的请求可能会返回诸如404错误(找不到页面)的信息,在这种情况下您将不会得到错误并且错误数据将大于0。200是一个很好的响应,您还可以检查StatusCode是否为404或其他任何值。

     [NSURLConnection
     sendAsynchronousRequest:urlRequest
     queue:[[NSOperationQueue alloc] init]
     completionHandler:^(NSURLResponse *response,
                         NSData *data,
                         NSError *error) 
    {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
     if ([data length] >0 && error == nil && [httpResponse statusCode] == 200)
     {

                    // DO YOUR WORK HERE

     }

4

由于sendAsynchronousRequest:urlRequest queue:queue completionHandler:已在iOS的9被弃用,并且它会建议使用NSURLSession-dataTaskWithRequest:completionHandler:替代。从iOS 7及更高版本开始可用。

原版的:

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 [NSURLConnection sendAsynchronousRequest:request
                                    queue:[NSOperationQueue mainQueue]
                        completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
     // ...
 }];

通过NSURLSession:

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [task resume];

2

sendAsynchronousRequest已在Swift中弃用。移至dataTaskWithRequest,幸运的是,它的使用方式几乎相同。

if let url = NSURL(string:"http://your_url") {

    let request:NSURLRequest = NSURLRequest(URL: url)
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config)

    let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

    });

    task.resume()
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.