Cocoa: Checks required for multiple asynchronous NSURLConnections using same delegate functions?

孤人 提交于 2019-11-28 03:52:22

Assuming you're launching all of the (asynchronous) connections on a single thread, then the delegate messages will all get posted in that thread's run loop. Therefore the delegate only needs to be able to deal with one message being handled at once; the run loop will hand one message off at a time. This means that while the order of the delegate messages is unknown and the next message could come from any connection object, there will be no concurrent execution of your delegate methods.

However, were you actually trying to use the same delegate object across multiple threads, rather than just using the asynchronous nature of the API, then you would need to deal with concurrent delegate methods.

I enhanced the Three20 library to implement asynchronous connections across multiple threads in order to fetch data even if the user was playing with the UI. After many hours of chasing down random memory leaks that were detected within the CFNetwork framework I finally root caused the issue. I was occasionally losing track of responses and data.

Any data structures which are accessed by multiple threads must be protected by an appropriate lock. If you are not using locks to access shared data structures in a mutually exclusive manner then you are not thread safe. See the "Using Locks" section of Apple's Threading Programming Guide.

The best solution is to subclass NSURLConnection and add instance variables to store its associated response and response data. In each connection delegate method you then cast the NSURLConnection to your subclass and access those instance variables. This is guaranteed to be mutually exclusive because every connection will be bundled with its own response and data. I highly recommend trying this since it is the cleanest solution. Here's the code from my implementation:

@interface TTURLConnection : NSURLConnection {
 NSHTTPURLResponse* _response;
 NSMutableData* _responseData;
}

@property(nonatomic,retain) NSHTTPURLResponse* response;
@property(nonatomic,retain) NSMutableData* responseData;

@end

@implementation TTURLConnection

@synthesize response = _response, responseData = _responseData;

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate {
 NSAssert(self != nil, @"self is nil!");

 // Initialize the ivars before initializing with the request
    // because the connection is asynchronous and may start
    // calling the delegates before we even return from this
    // function.

 self.response = nil;
 self.responseData = nil;

 self = [super initWithRequest:request delegate:delegate];
 return self;
}

- (void)dealloc {
 [self.response release];
 [self.responseData release];

 [super dealloc];
}

@end

/////////////////////////////////////////////////////////////////
////// NSURLConnectionDelegate

- (void)connection:(NSURLConnection*)connection
didReceiveResponse:(NSHTTPURLResponse*)response {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;
 ttConnection.response = response;
 ttConnection.responseData = [NSMutableData
                                 dataWithCapacity:contentLength];
}

- (void)connection:(NSURLConnection*)connection
    didReceiveData:(NSData*)data {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;
 [ttConnection.responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
 TTURLConnection* ttConnection = (TTURLConnection*)connection;

    if (ttConnection.response.statusCode == 200) {
        // Connection success
    }
}

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error {  
    TTURLConnection* ttConnection = (TTURLConnection*)connection;
    // Handle the error
}

Yes it's possible to have multiple connections. the notification object contains a pointer to the NSURLConnection that triggered the notification.

Internally I guess NSURLConnection listens to a socket and does something like this when it has data ready.

[your_delegate 
    performSelectorOnMainThread:@selector(connectionCallback:) 
    withObject:self 
    waitUntilDone:NO];

so you don't have to worry about it being multithreaded, NSURLConnection will take care of this. For simplicity I have written self, in the real world a NSNotification object is given.

You shouldn't have to do any checks related to multithreading.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!