Управление несколькими асинхронными соединениями NSURLConnection - PullRequest
88 голосов
/ 02 декабря 2008

У меня есть тонна повторяющегося кода в моем классе, который выглядит следующим образом:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
                                                              delegate:self];

Проблема с асинхронными запросами состоит в том, что когда у вас выполняются различные запросы, и у вас есть делегат, назначенный для обработки их всех как одного объекта, большое количество ветвлений и некрасивого кода начинает формулироваться следующим образом:

Какие данные мы получаем обратно? Если это содержит это, сделайте это, иначе сделайте другое. Думаю, было бы полезно пометить эти асинхронные запросы, как будто вы можете пометить представления с помощью идентификаторов.

Мне было любопытно, какая стратегия наиболее эффективна для управления классом, который обрабатывает несколько асинхронных запросов.

Ответы [ 13 ]

1 голос
/ 07 февраля 2009

Как указывают другие ответы, вы должны хранить где-то connectionInfo и искать их по connection.

Наиболее естественный тип данных для этого - 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];
0 голосов
/ 23 декабря 2013

Каждый NSURLConnection имеет атрибут hash, вы можете различать все по этому атрибуту.

Например, мне нужно хранить определенную информацию до и после подключения, поэтому мой 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];
}
0 голосов
/ 14 ноября 2012

Я решил создать подкласс 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
...