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 validation (which was introduced in iOS 5), but cancel it if the user changes the input field content in the mean time. What is the best way to cancel a current request?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With