Managing multiple asynchronous NSURLConnection con

2020-01-23 03:51发布

I have a ton of repeating code in my class that looks like the following:

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

The problem with asynchronous requests is when you have various requests going off, and you have a delegate assigned to treat them all as one entity, a lot of branching and ugly code begins to formulate going:

What kind of data are we getting back? If it contains this, do that, else do other. It would be useful I think to be able to tag these asynchronous requests, kind of like you're able to tag views with IDs.

I was curious what strategy is most efficient for managing a class that handles multiple asynchronous requests.

13条回答
爷的心禁止访问
2楼-- · 2020-01-23 04:07

in iOS5 and above you can just use the class method sendAsynchronousRequest:queue:completionHandler:

No need to keep track of connections since the response returns in the completion handler.

查看更多
乱世女痞
3楼-- · 2020-01-23 04:08

I have a project where I have two distinct NSURLConnections, and wanted to use the same delegate. What I did was create two properties in my class, one for each connection. Then in the delegate method, I check to see if which connection it is


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    if (connection == self.savingConnection) {
        [self.savingReturnedData appendData:data];
    }
    else {
        [self.sharingReturnedData appendData:data];
    }
}

This also allows me to cancel a specific connection by name when needed.

查看更多
仙女界的扛把子
4楼-- · 2020-01-23 04:08

Subclassing NSURLConnection to hold the data is clean, less code than some of the other answers, is more flexible, and requires less thought about reference management.

// 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

Use it as you would NSURLConnection and accumulate the data in its data property:

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

That's it.

If you want to go further you can add a block to serve as a callback with just a couple more lines of code:

// Add to DataURLConnection.h/.m
@property(nonatomic, copy) void (^onComplete)();

Set it like this:

DataURLConnection *con = [[DataURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
con.onComplete = ^{
    [self myMethod:con];
};
[con start];

and invoke it when loading is finished like this:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    ((DataURLConnection *)connection).onComplete();
}

You can extend the block to accept parameters or just pass the DataURLConnection as an argument to the method that needs it within the no-args block as shown

查看更多
兄弟一词,经得起流年.
5楼-- · 2020-01-23 04:08

THIS IS NOT A NEW ANSWER. PLEASE LET ME SHOW YOU HOW I DID

To distinguish different NSURLConnection within same class's delegate methods, I use NSMutableDictionary, to set and remove the NSURLConnection, using its (NSString *)description as key.

The object I chose for setObject:forKey is the unique URL that is used for initiating NSURLRequest, the NSURLConnection uses.

Once set NSURLConnection is evaluated at

-(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]];
查看更多
一纸荒年 Trace。
6楼-- · 2020-01-23 04:12

Every NSURLConnection has an hash attribute, you can discriminate all by this attribute.

For example i need to mantain certain information before and after connection, so my RequestManager have an NSMutableDictionary to do this.

An Example:

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

After request:

- (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];
}
查看更多
够拽才男人
7楼-- · 2020-01-23 04:13

Try my custom class, MultipleDownload, which handles all these for you.

查看更多
登录 后发表回答