У меня в классе много повторяющегося кода, который выглядит следующим образом:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
Проблема с асинхронными запросами заключается в том, что у вас выполняются различные запросы, и у вас есть делегат, которому назначено обрабатывать их все как одну сущность, много ветвлений и уродливый код начинает формулировать:
Какие данные мы возвращаем? Если он содержит это, сделайте это, иначе сделайте другое. Я думаю, было бы полезно иметь возможность помечать эти асинхронные запросы, как если бы вы могли помечать представления идентификаторами.
Мне было любопытно, какая стратегия наиболее эффективна для управления классом, который обрабатывает несколько асинхронных запросов.
источник
[NSMapTable weakToStrongObjectsMapTable]
вместо aCFMutableDictionaryRef
и сэкономить хлопоты. Хорошо сработало для меня.У меня есть проект, в котором у меня есть два разных NSURLConnection, и я хотел использовать один и тот же делегат. Я создал в своем классе два свойства, по одному для каждого соединения. Затем в методе делегата я проверяю, какое это соединение
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if (connection == self.savingConnection) { [self.savingReturnedData appendData:data]; } else { [self.sharingReturnedData appendData:data]; } }
Это также позволяет мне при необходимости отменить конкретное соединение по имени.
источник
Создание подкласса NSURLConnection для хранения данных является чистым, имеет меньше кода, чем некоторые другие ответы, является более гибким и требует меньше размышлений об управлении ссылками.
// DataURLConnection.h #import <Foundation/Foundation.h> @interface DataURLConnection : NSURLConnection @property(nonatomic, strong) NSMutableData *data; @end // DataURLConnection.m #import "DataURLConnection.h" @implementation DataURLConnection @synthesize data; @end
Используйте его так же, как NSURLConnection, и накапливайте данные в его свойстве data:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { ((DataURLConnection *)connection).data = [[NSMutableData alloc] init]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [((DataURLConnection *)connection).data appendData:data]; }
Вот и все.
Если вы хотите пойти дальше, вы можете добавить блок, который будет выполнять функцию обратного вызова, с помощью еще пары строк кода:
// Add to DataURLConnection.h/.m @property(nonatomic, copy) void (^onComplete)();
Установите это так:
DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; con.onComplete = ^{ [self myMethod:con]; }; [con start];
и вызвать его, когда загрузка завершится следующим образом:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { ((DataURLConnection *)connection).onComplete(); }
Вы можете расширить блок для приема параметров или просто передать DataURLConnection в качестве аргумента методу, который в нем нуждается, в блоке no-args, как показано
источник
ЭТО НЕ НОВЫЙ ОТВЕТ. ПОЖАЛУЙСТА, ДАЙТЕ МНЕ ПОКАЗАТЬ ВАМ, КАК Я ДЕЛАЛ
Чтобы различать разные NSURLConnection в методах делегата одного и того же класса, я использую NSMutableDictionary, чтобы установить и удалить NSURLConnection, используя его в
(NSString *)description
качестве ключа.Объект, который я выбрал,
setObject:forKey
- это уникальный URL-адрес, который используется для запускаNSURLRequest
,NSURLConnection
uses.После установки NSURLConnection оценивается на
-(void)connectionDidFinishLoading:(NSURLConnection *)connection, it can be removed from the dictionary. // This variable must be able to be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection NSMutableDictionary *connDictGET = [[NSMutableDictionary alloc] init]; //...// // You can use any object that can be referenced from - (void)connectionDidFinishLoading:(NSURLConnection *)connection [connDictGET setObject:anyObjectThatCanBeReferencedFrom forKey:[aConnectionInstanceJustInitiated description]]; //...// // At the delegate method, evaluate if the passed connection is the specific one which needs to be handled differently if ([[connDictGET objectForKey:[connection description]] isEqual:anyObjectThatCanBeReferencedFrom]) { // Do specific work for connection // } //...// // When the connection is no longer needed, use (NSString *)description as key to remove object [connDictGET removeObjectForKey:[connection description]];
источник
Один из моих подходов - не использовать один и тот же объект в качестве делегата для каждого соединения. Вместо этого я создаю новый экземпляр моего класса синтаксического анализа для каждого отключенного соединения и устанавливаю делегат для этого экземпляра.
источник
Попробуйте мой собственный класс MultipleDownload , который все это сделает за вас.
источник
Обычно я создаю массив словарей. Каждый словарь имеет бит идентифицирующей информации, объект NSMutableData для хранения ответа и само соединение. Когда срабатывает метод делегата соединения, я ищу словарь соединения и обрабатываю его соответствующим образом.
источник
Один из вариантов - просто создать подкласс NSURLConnection самостоятельно и добавить -tag или аналогичный метод. Дизайн NSURLConnection намеренно очень простой, поэтому это вполне приемлемо.
Или, возможно, вы могли бы создать класс MyURLConnectionController, который отвечает за создание и сбор данных подключения. Тогда ему нужно будет только сообщить вашему основному объекту контроллера после завершения загрузки.
источник
в iOS5 и выше вы можете просто использовать метод класса
sendAsynchronousRequest:queue:completionHandler:
Нет необходимости отслеживать соединения, поскольку ответ возвращается в обработчике завершения.
источник
Мне нравится ASIHTTPRequest .
источник
Как указано в других ответах, вы должны где-то хранить connectionInfo и искать их по подключению.
Наиболее естественный тип данных для этого
NSMutableDictionary
, но он не может приниматьNSURLConnection
качестве ключей, поскольку соединения не копируются.Другой вариант для использования в
NSURLConnections
качестве ключей вNSMutableDictionary
используетNSValue valueWithNonretainedObject]
:NSMutableDictionary* dict = [NSMutableDictionary dictionary]; NSValue *key = [NSValue valueWithNonretainedObject:aConnection] /* store: */ [dict setObject:connInfo forKey:key]; /* lookup: */ [dict objectForKey:key];
источник
Я решил создать подкласс NSURLConnection и добавить тег, делегат и NSMutabaleData. У меня есть класс DataController, который обрабатывает все управление данными, включая запросы. Я создал протокол DataControllerDelegate, чтобы отдельные представления / объекты могли прослушивать DataController, чтобы узнать, когда их запросы были завершены, и, если необходимо, сколько было загружено или ошибок. Класс DataController может использовать подкласс NSURLConnection для запуска нового запроса и сохранения делегата, который хочет прослушать DataController, чтобы узнать, когда запрос завершен. Это мое рабочее решение в XCode 4.5.2 и ios 6.
Файл DataController.h, объявляющий протокол DataControllerDelegate). DataController также является одноэлементным:
@interface DataController : NSObject @property (strong, nonatomic)NSManagedObjectContext *context; @property (strong, nonatomic)NSString *accessToken; +(DataController *)sharedDataController; -(void)generateAccessTokenWith:(NSString *)email password:(NSString *)password delegate:(id)delegate; @end @protocol DataControllerDelegate <NSObject> -(void)dataFailedtoLoadWithMessage:(NSString *)message; -(void)dataFinishedLoading; @end
Ключевые методы в файле DataController.m:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidReceiveResponse from %@", customConnection.tag); [[customConnection receivedData] setLength:0]; } -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidReceiveData from %@", customConnection.tag); [customConnection.receivedData appendData:data]; } -(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"connectionDidFinishLoading from %@", customConnection.tag); NSLog(@"Data: %@", customConnection.receivedData); [customConnection.dataDelegate dataFinishedLoading]; } -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSURLConnectionWithDelegate *customConnection = (NSURLConnectionWithDelegate *)connection; NSLog(@"DidFailWithError with %@", customConnection.tag); NSLog(@"Error: %@", [error localizedDescription]); [customConnection.dataDelegate dataFailedtoLoadWithMessage:[error localizedDescription]]; }
И чтобы начать запрос:
[[NSURLConnectionWithDelegate alloc] initWithRequest:request delegate:self startImmediately:YES tag:@"Login" dataDelegate:delegate];
NSURLConnectionWithDelegate.h: @protocol DataControllerDelegate;
@interface NSURLConnectionWithDelegate : NSURLConnection @property (strong, nonatomic) NSString *tag; @property id <DataControllerDelegate> dataDelegate; @property (strong, nonatomic) NSMutableData *receivedData; -(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate; @end
И NSURLConnectionWithDelegate.m:
#import "NSURLConnectionWithDelegate.h" @implementation NSURLConnectionWithDelegate -(id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString *)tag dataDelegate:(id)dataDelegate { self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately]; if (self) { self.tag = tag; self.dataDelegate = dataDelegate; self.receivedData = [[NSMutableData alloc] init]; } return self; } @end
источник
У каждого NSURLConnection есть атрибут хэша, вы можете различить все по этому атрибуту.
Например, мне нужно сохранить определенную информацию до и после подключения, поэтому у моего RequestManager есть NSMutableDictionary для этого.
Пример:
// Make Request NSURLRequest *request = [NSURLRequest requestWithURL:url]; NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // Append Stuffs NSMutableDictionary *myStuff = [[NSMutableDictionary alloc] init]; [myStuff setObject:@"obj" forKey:@"key"]; NSNumber *connectionKey = [NSNumber numberWithInt:c.hash]; [connectionDatas setObject:myStuff forKey:connectionKey]; [c start];
По запросу:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"Received %d bytes of data",[responseData length]); NSNumber *connectionKey = [NSNumber numberWithInt:connection.hash]; NSMutableDictionary *myStuff = [[connectionDatas objectForKey:connectionKey]mutableCopy]; [connectionDatas removeObjectForKey:connectionKey]; }
источник