iOS start Background Thread
Solution 1
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.
Solution 2
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
Solution 3
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.
Solution 4
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.
Solution 5
Swift 2.x answer:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
self.getResultSetFromDB(docids)
}
Srikar Appalaraju
Hi I am Srikar, I think I have been programmed to feel that I need to write this message...
Updated on May 13, 2020Comments
-
Srikar Appalaraju almost 4 years
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; }
-
csiu over 12 yearsWhat error / crash log do you get?
-
Srikar Appalaraju over 12 yearsPlease see my updates...
-
Rog over 12 yearsCan you please show the method you are calling in the background? And make sure the object
docids
is retained. -
Srikar Appalaraju over 12 yearsyes,
docids
areretain
. I have put it in.h
as@property (nonatomic, retain) NSMutableArray *docids;
-
bbum over 12 yearsDon't prefix methods with
get
; that should just beresultSetFromDB:
-
-
Nicolas S over 12 yearsPlease copy the line you used that run smoothly on main thread.
-
Srikar Appalaraju over 12 yearsI use this from main thread & atleast it hits that method instead of abruptly crashing -
[self getResultSetFromDB:docids];
-
Nicolas S over 12 yearshave you enabled what i told you?
-
Nicolas S over 12 yearsPut a breakpoint in this line: SpotMain *mirror = [[SpotMain alloc] init]; and tell me if its hit and, if tehn, which line crashes. Enable zombies please so we can get a clear error log.
-
Srikar Appalaraju over 12 yearsyes, I have enabled zombies. I get this - ` 2011-08-14 12:49:42.697 FLO[16211:707] *** -[FMResultSet release]: message sent to deallocated instance 0x2bff80 2011-08-14 12:49:42.697 FLO[16211:1607] *** __NSAutoreleaseNoPool(): Object 0x2c0cc0 of class __NSCFData autoreleased with no pool in place - just leaking
. Also when I try to call this method from background thread I do not reach
SpotMain *mirror...`, It crashes soon after entering the background thread... -
Srikar Appalaraju over 12 yearscool! didn't know this. Does this apply to
[NSThread detachNewThreadSelector:@selector....
also? -
Scott Forbes over 12 yearsThis is not a zombie-related problem. The problem is that, if you create a new thread using
performSelectorInBackground:withObject
, your new thread doesn't have an autorelease pool (unless you create one manually). Hence the error message about autoreleasing an object with no pool in place. -
Scott Forbes over 12 yearsYes. Per the Apple docs, calling
performSelectorInBackground:withObject:
"is the same as if you called thedetachNewThreadSelector:toTarget:withObject:
method ofNSThread
with the current object, selector, and parameter object as parameters." -
Sti about 10 yearsIs there a difference between
(unsigned long)NULL
and0
in this matter? -
Jawad Al Shaikh almost 10 years@Sti from apple Dev Docs: Note: The second argument to the dispatch_get_global_queue function is reserved for future expansion. For now, you should always pass 0 for this argument.
-
Ilya Denisov about 9 yearsShould I then use performSelectorOnMainThread to update UI with operation results or there is more consistent way to update UI with GCD?
-
OhadM almost 9 yearsAlso, you can change the flag from DISPATCH_QUEUE_PRIORITY_DEFAULT to DISPATCH_QUEUE_PRIORITY_BACKGROUND