Objective c 管理多个异步连接
我的类中有大量重复代码,如下所示:Objective c 管理多个异步连接,objective-c,iphone,cocoa,cocoa-touch,nsurlconnection,Objective C,Iphone,Cocoa,Cocoa Touch,Nsurlconnection,我的类中有大量重复代码,如下所示: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 异步请求的问题是,当您有各种请求发出,并且您分配了一个委托将它们作为一个实体来处理时,许多分支和丑陋的代码开始出现: 我们得到的是什么样的数据?如果
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
异步请求的问题是,当您有各种请求发出,并且您分配了一个委托将它们作为一个实体来处理时,许多分支和丑陋的代码开始出现:
我们得到的是什么样的数据?如果它包含此项,则执行该项,否则执行其他项。我认为能够标记这些异步请求会很有用,就像能够用ID标记视图一样
我很好奇,对于管理处理多个异步请求的类,什么策略最有效。我通常创建一个字典数组。每个字典都有一点标识信息、一个存储响应的NSMutableData对象以及连接本身。当启动连接委托方法时,我会查找连接的字典并相应地处理它 我跟踪由与其关联的NSURLConnection键入的CFMutableDictionaryRef中的响应。i、 e:
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];
}
一个选择就是自己创建NSURLConnection子类,并添加一个-tag或类似的方法。NSURLConnection的设计非常简单,因此完全可以接受
或者,您可以创建一个MyURLConnectionController类,负责创建和收集连接的数据。加载完成后,它只需通知您的主控制器对象。我采取的一种方法是不对每个连接使用与委托相同的对象。相反,我为触发的每个连接创建一个解析类的新实例,并将委托设置为该实例。尝试我的自定义类,它可以为您处理所有这些问题。正如其他答案所指出的,您应该将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,我使用NSMutableDictionary来设置和删除NSURLConnection,并使用其
(NSString*)描述作为键
我为setObject:forKey
选择的对象是用于启动NSURLRequest
的唯一URL,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]];
我有一个项目,其中我有两个不同的NSURLConnection,并且希望使用同一个委托。我所做的是在我的类中创建两个属性,每个连接一个。然后在委托方法中,我检查它是否是连接
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (connection == self.savingConnection) {
[self.savingReturnedData appendData:data];
}
else {
[self.sharingReturnedData appendData:data];
}
}
这还允许我在需要时按名称取消特定连接。我决定将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
并启动请求:[[nsurconnectionwithdelegate alloc]initWithRequest:request delegate:self startimmediate:YES标记:@“Login”dataDelegate:delegate]代码>
NSURLConnectionWithDelegate.h:
@协议数据控制器
@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
在iOS5及更高版本中,您可以只使用class方法
sendAsynchronousRequest:queue:completionHandler:
无需跟踪连接,因为响应会在完成处理程序中返回。将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
就这样
如果您想更进一步,可以添加一个块作为回调,只需再添加几行代码:
// 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 *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都有一个散列属性,您可以通过该属性区分所有
例如,我需要在连接前后保存某些信息,所以我的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];
}
本,可以向你要一段示例代码吗?我试着想象一下你是怎么做的,但还没有完全做到。尤其是本,你是怎么查字典的?因为NSURLConnection没有实现NSCopying(所以它不能用作键),所以你不能拥有字典字典
- (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];
}