Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 管理多个异步连接_Objective C_Iphone_Cocoa_Cocoa Touch_Nsurlconnection - Fatal编程技术网

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];
}