pipe理多个asynchronousNSURLConnection连接
我在课堂上有很多重复的代码,如下所示:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
asynchronous请求的问题是,当你有各种各样的请求时,你有一个委托给他们作为一个实体,很多分支和丑陋的代码开始制定:
我们回来了什么样的数据? 如果它包含这个,那么做别的。 我认为能够标记这些asynchronous请求非常有用,就像您可以使用ID标记视图一样。
我很好奇什么策略对于pipe理处理多个asynchronous请求的类来说效率最高。
我跟踪由与其关联的NSURLConnection键入的CFMutableDictionaryRef中的响应。 即:
connectionToInfoMapping = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
这可能看起来很奇怪,而不是NSMutableDictionary,但我这样做,因为此CFDictionary只保留其键(NSURLConnection),而NSDictionary复制其键(和NSURLConnection不支持复制)。
一旦完成:
CFDictionaryAddValue( connectionToInfoMapping, connection, [NSMutableDictionary dictionaryWithObject:[NSMutableData data] forKey:@"receivedData"]);
现在我有一个关于每个连接的数据的“信息”字典,我可以使用它来跟踪有关连接的信息,“信息”字典中已经包含一个可用于存储回复数据的可变数据对象。
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSMutableDictionary *connectionInfo = CFDictionaryGetValue(connectionToInfoMapping, connection); [[connectionInfo objectForKey:@"receivedData"] appendData:data]; }
我有一个项目,我有两个不同的NSURLConnections,并希望使用相同的代表。 我所做的是在我的课堂上创build两个属性,每个连接一个。 然后在委托方法中,我检查是否是连接
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { if (connection == self.savingConnection) { [self.savingReturnedData appendData:data]; } else { [self.sharingReturnedData appendData:data]; } }
这也允许我在需要时按名称取消特定的连接。
inheritanceNSURLConnection来保存数据是干净的,比其他一些答案less的代码,更加灵活,而且对参考pipe理的要求也较less。
// 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一样使用它,并在其数据属性中累积数据:
- (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]; }
而已。
如果你想进一步,你可以添加一个块作为一个callback只有几行代码:
// 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作为parameter passing给在no-args块内需要它的方法,如图所示
这不是一个新的答案。 请让我告诉你我是怎么做的
为了区分同一个类的委托方法中不同的NSURLConnection,我使用NSMutableDictionary来设置和删除NSURLConnection,使用它的(NSString *)description
作为关键字。
我为setObject:forKey
select的对象是用于启动NSURLRequest
的NSURLConnection
使用的唯一URL。
一旦设置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]];
我采取的一种方法是不使用相同的对象作为委托为每个连接。 相反,我为每个被触发的连接创build了一个新的parsing类实例,并将委托设置为该实例。
试试我的自定义类, MultipleDownload ,它为您处理所有这些。
我通常会创build一个字典arrays。 每个字典都有一些识别信息,一个存储响应的NSMutableData对象,以及连接本身。 当连接委托方法触发时,我查找连接的字典并相应地处理它。
一个select就是自己inheritanceNSURLConnection并添加一个-tag或类似的方法。 NSURLConnection的devise是故意非常裸露的骨头,所以这是完全可以接受的。
或者也许你可以创build一个负责创build和收集连接数据的MyURLConnectionController类。 一旦加载完成,它只需要通知你的主控制器对象。
在iOS5及以上版本中,您可以使用类方法sendAsynchronousRequest:queue:completionHandler:
由于响应在完成处理程序中返回,因此无需跟踪连接。
我喜欢ASIHTTPRequest 。
正如其他答案所指出的那样,你应该将connectionInfo存储在某个地方,并通过连接来查找它们。
最自然的数据types是NSMutableDictionary
,但不能接受NSURLConnection
作为键,因为连接是不可复制的。
在NSMutableDictionary
使用NSURLConnections
作为键的另一种select是使用NSValue valueWithNonretainedObject]
:
NSMutableDictionary* dict = [NSMutableDictionary dictionary]; NSValue *key = [NSValue valueWithNonretainedObject:aConnection] /* store: */ [dict setObject:connInfo forKey:key]; /* lookup: */ [dict objectForKey:key];
我决定inheritanceNSURLConnection并添加一个标记,委托和一个NSMutabaleData。 我有一个DataController类来处理所有的数据pipe理,包括请求。 我创build了一个DataControllerDelegate协议,以便单独的视图/对象可以监听DataController,以了解他们的请求何时完成,以及是否需要多less下载或错误。 DataController类可以使用NSURLConnection子类来启动一个新的请求,并保存要监听DataController的委托来知道请求何时完成。 这是我在XCode 4.5.2和iOS 6中的工作解决scheme。
声明DataControllerDelegate协议的DataController.h文件)。 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]; }