我班上有很多重复的代码,如下所示:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
异步请求的问题在于,当您有各种请求消失,并且您指定了一个委托将它们全部视为一个实体时,许多分支和丑陋的代码开始形成:
我们回来了什么样的数据?如果它包含这个,那就做,否则做其他。我认为能够标记这些异步请求会很有用,就像你能够使用ID标记视图一样。
我很好奇什么策略对于管理处理多个异步请求的类最有效。
答案 0 :(得分:77)
我跟踪由与之关联的NSURLConnection键入的CFMutableDictionaryRef中的响应。即:
connectionToInfoMapping =
CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
使用它代替NSMutableDictionary似乎很奇怪,但我这样做是因为这个CFDictionary只保留其键(NSURLConnection),而NSDictionary复制其键(NSURLConnection不支持复制)。
完成后:
CFDictionaryAddValue(
connectionToInfoMapping,
connection,
[NSMutableDictionary
dictionaryWithObject:[NSMutableData data]
forKey:@"receivedData"]);
现在我有一个“info”数据字典用于每个连接,我可以用它来跟踪有关连接的信息,“info”字典已经包含一个可变数据对象,我可以使用它来存储回复数据,因为它进来了。
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSMutableDictionary *connectionInfo =
CFDictionaryGetValue(connectionToInfoMapping, connection);
[[connectionInfo objectForKey:@"receivedData"] appendData:data];
}
答案 1 :(得分:19)
我有一个项目,我有两个不同的NSURLConnections,并希望使用相同的委托。我所做的是在我的类中创建两个属性,每个连接一个。然后在委托方法中,我检查它是否是
的连接
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (connection == self.savingConnection) {
[self.savingReturnedData appendData:data];
}
else {
[self.sharingReturnedData appendData:data];
}
}
这也允许我在需要时按名称取消特定连接。
答案 2 :(得分:16)
对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一样使用它并在其数据属性中累积数据:
- (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块中需要它的方法,如图所示
答案 3 :(得分:8)
这不是一个新的答案。请让我看看我怎么做
为了区分同一个类的委托方法中的不同NSURLConnection,我使用NSMutableDictionary来设置和删除NSURLConnection,使用其(NSString *)description
作为键。
我为setObject:forKey
选择的对象是用于发起NSURLRequest
的唯一网址,NSURLConnection
使用。
设置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]];
答案 4 :(得分:5)
我采取的一种方法是不为每个连接使用与委托相同的对象。相反,我为每个被触发的连接创建了一个新的解析类实例,并将委托设置为该实例。
答案 5 :(得分:4)
尝试我的自定义类MultipleDownload,它会为您处理所有这些。
答案 6 :(得分:2)
我通常会创建一个字典数组。每个字典都有一些标识信息,一个用于存储响应的NSMutableData对象以及连接本身。当连接委托方法触发时,我查找连接的字典并相应地处理它。
答案 7 :(得分:2)
一个选项就是自己继承NSURLConnection并添加-tag或类似的方法。 NSURLConnection的设计是故意非常简单的骨骼,所以这是完全可以接受的。
或许您可以创建一个负责创建和收集连接数据的MyURLConnectionController类。然后,只需在加载完成后通知您的主控制器对象。
答案 8 :(得分:2)
在iOS5及以上版本中,您只需使用class方法即可
sendAsynchronousRequest:queue:completionHandler:
由于响应在完成处理程序中返回,因此无需跟踪连接。
答案 9 :(得分:1)
正如其他答案所指出的那样,你应该将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];
答案 10 :(得分:1)
我喜欢ASIHTTPRequest。
答案 11 :(得分:0)
我决定继承NSURLConnection并添加标签,委托和NSMutabaleData。我有一个DataController类来处理所有数据管理,包括请求。我创建了一个DataControllerDelegate协议,以便各个视图/对象可以监听DataController以查明其请求何时完成,以及是否需要下载了多少或错误。 DataController类可以使用NSURLConnection子类来启动新请求,并保存想要侦听DataController的委托以了解请求何时完成。这是我在XCode 4.5.2和ios 6中的工作解决方案。
声明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
答案 12 :(得分:0)
每个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];
}