NSURLConnection - data comes in after completion
NSURLConnection - data comes in after completion
- Subject: NSURLConnection - data comes in after completion
- From: Fritz Anderson <email@hidden>
- Date: Mon, 2 Aug 2010 11:40:27 -0500
iOS 4.0.1 SDK, Simulator 4.0. The behavior matches a bug report on 3.x device.
I have a problem with NSURLConnection that I've solved, but I don't trust the solution, so I'd like some assurance that I'm doing the right thing.
As you see in the code excerpt, I start a download asynchronously, with self as the delegate. I allocate an NSMutableData object to accumulate the downloaded data. Data goes into the accumulator in the connection:didReceiveData: callback.
The didReceiveData: callback asserts that the data accumulator exists. In certain circumstances (it seems to be with four of these requests started nearly simultaneously), the assertion is triggered. self.dataAccumulator is nil, and there is a significant amount of data coming in - 30K out of a 200K image.
One of the places I nil-out dataAccumulator is in the connectionDidFinishLoading: callback. I find that if I cancel the connection in the didFinishLoading/didFailWithError callbacks, the bug goes away. And, despite apparently missing incoming data (which seemed to have been arriving after the download had completed or failed), the data that did accumulate is correct and complete.
So okay, the error is silenced. But I'm not happy. I don't understand why additional, and apparently duplicative, data should be coming in after the completion callback. Isn't the download supposed to be... complete? Why should I have to cancel a connection on which NSURLConnection says there should be no more traffic?
— F
@property(nonatomic, copy) NSURL * url;
@property(nonatomic, retain) NSURLConnection * downloadConnection;
@property(nonatomic, retain) NSMutableData * dataAccumulator;
- (void) loadAsync
{
self.dataAccumulator = [NSMutableData data];
// The URL scheme is http:.
NSURLRequest * req = [NSURLRequest requestWithURL: self.url];
self.downloadConnection = [NSURLConnection connectionWithRequest: req
delegate: self];
[self.downloadConnection start];
}
#pragma mark -
#pragma mark NSURLConnectionDelegate
- (void) connection: (NSURLConnection *) connection
didReceiveData: (NSData *) data
{
// I'd better have a place to put the data:
NSAssert1(self.dataAccumulator,
@"%s: No data accumulator",
__PRETTY_FUNCTION__);
// In the bug, this assertion fires.
// Accumulate the incoming data.
[self.dataAccumulator appendData: data];
}
- (void) connectionDidFinishLoading: (NSURLConnection *) connection
{
//////////////////////////////////////
[self.downloadConnection cancel]; // This shouldn't be necessary.
//////////////////////////////////////
// ... do something with the contents of self.dataAccumulator.
// This would include creating a UIImage and writing the data
// to a cache file. Then...
// Get rid of the temporary data.
self.dataAccumulator = nil;
// Clean up the download connection.
// Don't absolutely release it in one of its callbacks...
[[self.downloadConnection retain] autorelease];
// ... but do release my hold on it.
self.downloadConnection = nil;
// Believe me, I'd like to nil-out the NSURLConnection's
// delegate reference, but that's not in the class's API.
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden