Как я могу отменить асинхронный вызов через NSURLConnection sendAsynchronousRequest? - PullRequest
6 голосов
/ 10 ноября 2011

У меня есть вызов веб-службы, выполняющий некоторую проверку ввода пользователя в режиме реального времени.Я хотел бы использовать [NSURLConnection sendAsynchronousRequest] для проверки (которая была введена в iOS 5), но отмените ее, если пользователь в это время меняет содержимое поля ввода.Каков наилучший способ отменить текущий запрос?

Ответы [ 2 ]

19 голосов
/ 10 ноября 2011

Не похоже, что есть хороший способ сделать это. Похоже, решение состоит в том, чтобы не использовать новый [NSURLConnection sendAsynchronousRequest] в ситуациях, когда вам нужно отменить запрос.

3 голосов
/ 17 декабря 2011

Мне удалось сделать это, поместив метод sendAsynchronousRequest в отдельный класс DownloadWrapper следующим образом:

//
//  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

Чтобы использовать этот класс, я делаю следующее, в дополнение к объявлениюDownloadWrapper *downloadWrapper переменная (в объявлении интерфейса) и реализация методов протокола, которые обрабатывают ответ или его отсутствие:

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

Затем я просто делаю следующее, чтобы «отменить» соединение, когда представление являетсявот-вот исчезнет:

- (void)viewDidUnload
{
    [super viewDidUnload];
    downloadWrapper = nil;
}

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

Это так просто.Мы надеемся, что это имитирует документированный метод cancel, в котором говорится, что он выполняет следующее:

После вызова этого метода делегат получателя больше не будет получать никаких сообщений для этого NSURLConnection.

Меня беспокоило, что этот (несколько наивный) метод означает, что пакеты данных все равно будут проходить в ответ на наш URL-запрос - только то, что мы больше не «слушаем» как делегат.Но потом я понял, что после того, как URL-запрос был отправлен, на самом деле нет никакого способа остановить возвращение ответа нам - мы можем только игнорировать его (если не на этом уровне, то все еще на каком-то более низком уровне в сетевой иерархии),Пожалуйста, поправьте меня, если я ошибаюсь.

В любом случае, надеюсь, это поможет.

...