How can I cancel an asynchronous call through NSURLConnection sendAsynchronousRequest?

前端 未结 2 939
星月不相逢
星月不相逢 2020-12-03 16:21

I\'ve got a web service call performing some validation on user input in real time. I\'d like to use [NSURLConnection sendAsynchronousRequest] on the validatio

相关标签:
2条回答
  • 2020-12-03 16:44

    I've managed to do this by placing the sendAsynchronousRequest method in a separate DownloadWrapper class, as follows:

    //
    //  DownloadWrapper.h
    //
    //  Created by Ahmed Khalaf on 16/12/11.
    //  Copyright (c) 2011 arkuana. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @protocol DownloadWrapperDelegate
    - (void)receivedData:(NSData *)data;
    - (void)emptyReply;
    - (void)timedOut;
    - (void)downloadError:(NSError *)error;
    @end
    
    @interface DownloadWrapper : NSObject {
        id<DownloadWrapperDelegate> delegate;
    }
    @property(nonatomic, retain) id<DownloadWrapperDelegate> delegate;
    - (void)downloadContentsOfURL:(NSString *)urlString;
    @end
    
    @implementation DownloadWrapper
    @synthesize delegate;
    
    - (void)downloadContentsOfURL:(NSString *)urlString
    {
        NSURL *url = [NSURL URLWithString:urlString];
    
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:TIMEOUT_INTERVAL];
        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];
        }];
    }
    @end
    

    To utilise this class, I do the following, in addition to declaring the DownloadWrapper *downloadWrapper variable (in the interface declaration) and implementing the protocol methods which handles the response or a lack of one:

    NSString *urlString = @"http://yoursite.com/page/to/download.html";
    downloadWrapper = [DownloadWrapper alloc];
    downloadWrapper.delegate = self;
    [downloadWrapper downloadContentsOfURL:urlString];
    

    Then I simply do the following to 'cancel' the connection when the view is about to disappear:

    - (void)viewDidUnload
    {
        [super viewDidUnload];
        downloadWrapper = nil;
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
        [downloadWrapper setDelegate:nil];
    }
    

    It's as simple as that. This would hopefully mimic the documented cancel method, which states that it does the following:

    Once this method is called, the receiver’s delegate will no longer receive any messages for this NSURLConnection.

    I was concerned that this (somewhat naive) method means that the packets of data would still come through in response to our URL request - only that we're no longer 'listening in' as the delegate. But then I realised that once the URL request was sent through, there's really no way of stopping the response from coming back to us - we can only disregard it (if not at this level, then still at some lower level in the network hierarchy). Please correct me if I'm wrong.

    Either way, hope this helps.

    0 讨论(0)
  • 2020-12-03 16:45

    It doesn't appear that there is a good way to do this. The solution seems to be to not use the new [NSURLConnection sendAsynchronousRequest] in situations in which you need to cancel the request.

    0 讨论(0)
提交回复
热议问题