I have a class that updates two .plist files in the app documents directory via an NSURLConnection. The class acts as its own delegate for NSURLConnection. It works properly when I ask for a single file, but fails when I try to update two files. Does it look like I should start a new thread for each of the getNewDatabase messages?
- (void)getAllNewDatabases {
[self performSelectorOnMainThread:@selector(getNewDatabase:) withObject:@"file1" waitUntilDone:YES];
[self performSelectorOnMainThread:@selector(getNewDatabase:) withObject:@"file2" waitUntilDone:YES];
}
- (BOOL)getNewDatabase:(NSString *)dbName
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableString *apiString = [[NSMutableString alloc] initWithString:kAPIHost];
[apiString appendFormat:@"/%@.plist",dbName];
NSURLRequest *myRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:apiString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *myConnection = [[NSURLConnection alloc] initWithRequest:myRequest delegate:self];
[apiString release];
if( myConnection )
{
//omitted for clarity here
}
[pool release];
}
//NSURLConnection delegate methods here ...
I found something interesting with NSURLConnection and NSThread - the thread will only live as long as it takes to perform the method that you call from it.
In the case above the thread will live only as long as getNewDatabase:(NSString *)dbName
takes to complete, therefore killing off any of its delegate methods before they actually have time to do anything.
I found this website that gives a better explanation and a solution to the problem
I tweaked it a little bit so I could have a custom time out if it didn't complete in a given time frame (handy when someone is walking around between access points)
start = [NSDate dateWithTimeIntervalSinceNow:3];
while(!isFinished && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate distantFuture]]){
if([start compare:[NSDate date]] == NSOrderedAscending){
isFinished = YES;
}
}
As it stands currently in the code you provided, getNewDatabase:
is running on the main thread of your application. The problem in this particular case then is something other than the life cycle of the thread, as James observed in his case.
If you did intend to perform this operation in the background, I'd recommend looking into using NSOperationQueue
and NSOperation
rather than solving the problem with the current code. I think your case is a great fit for NSOperationQueue
, especially given that you have more than one download task to perform.
Dave Dribin has an excellent article about using asynchronous API, such as NSURLConnection, inside an NSOperation
. Alternatively, as long as you're running in a background thread, you can also simplify the process and just use a synchronous API method instead in your NSOperation, such as initWithContentsOfURL:
.
Marcus Zarra has also written a tutorial that demonstrates how easy it is to incorporate and use NSOperationQueue for simple background operations.