I have a small sqlitedb in my iOS device. When a user presses a button, I fetch the data from sqlite & show it to user.
This fetching part I want to do it in a background thread (to not block the UI main thread). I do this like so -
[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];
After the fetching & a little bit of processing, I need to update the UI. But since (as a good practice) we should not perform UI updation from background threads. I call a selector
on mainthread like so -
[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
But my App crashes in the first step. i.e. starting a background thread. Is this not a way to start background threads in iOS?
UPDATE 1: After [self performSelectorInBackground....
I get this stacktrace, no info what so ever -
UPDATE 2: I even tried, starting a background thread like so -
[NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];
but still I get same stacktrace.
Just so that I clarify, when I perform this operation on main thread everything runs smooth...
UPDATE 3 This is the method I am trying to run from background
- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids
{
SpotMain *mirror = [[SpotMain alloc] init];
NSMutableArray *filteredDocids = toProceessDocids;
if(![gMediaBucket isEqualToString:@""])
filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1];
if(![gMediaType isEqualToString:@""])
filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1];
if(![gPlatform isEqualToString:@""])
filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1];
self.resultSet = [mirror FetchObjectFromDocid:filteredDocids];
[filteredDocids release];
[mirror release];
[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
return;
}
This question is related to
objective-c
ios
multithreading
uikit
core-foundation
If you use performSelectorInBackground:withObject:
to spawn a new thread, then the performed selector is responsible for setting up the new thread's autorelease pool, run loop and other configuration details – see "Using NSObject to Spawn a Thread" in Apple's Threading Programming Guide.
You'd probably be better off using Grand Central Dispatch, though:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self getResultSetFromDB:docids];
});
GCD is a newer technology, and is more efficient in terms of memory overhead and lines of code.
Updated with a hat tip to Chris Nolet, who suggested a change that makes the above code simpler and keeps up with Apple's latest GCD code examples.
Well that's pretty easy actually with GCD. A typical workflow would be something like this:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
// Perform async operation
// Call your method/function here
// Example:
// NSString *result = [anObject calculateSomething];
dispatch_sync(dispatch_get_main_queue(), ^{
// Update UI
// Example:
// self.myLabel.text = result;
});
});
For more on GCD you can take a look into Apple's documentation here
Enable NSZombieEnabled to know which object is being released and then accessed.
Then check if the getResultSetFromDB:
has anything to do with that. Also check if docids
has anything inside and if it is being retained.
This way you can be sure there is nothing wrong.
The default sqlite library that comes with iOS is not compiled using the SQLITE_THREADSAFE macro on. This could be a reason why your code crashes.
Swift 2.x answer:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
self.getResultSetFromDB(docids)
}
Source: Stackoverflow.com