iOS start Background Thread

171,222

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)
    }
Share:
171,222
Srikar Appalaraju
Author by

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, 2020

Comments

  • Srikar Appalaraju
    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 -

    enter image description here

    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
      csiu over 12 years
      What error / crash log do you get?
    • Srikar Appalaraju
      Srikar Appalaraju over 12 years
      Please see my updates...
    • Rog
      Rog over 12 years
      Can you please show the method you are calling in the background? And make sure the object docids is retained.
    • Srikar Appalaraju
      Srikar Appalaraju over 12 years
      yes, docids are retain. I have put it in .h as @property (nonatomic, retain) NSMutableArray *docids;
    • bbum
      bbum over 12 years
      Don't prefix methods with get; that should just be resultSetFromDB:
  • Nicolas S
    Nicolas S over 12 years
    Please copy the line you used that run smoothly on main thread.
  • Srikar Appalaraju
    Srikar Appalaraju over 12 years
    I use this from main thread & atleast it hits that method instead of abruptly crashing - [self getResultSetFromDB:docids];
  • Nicolas S
    Nicolas S over 12 years
    have you enabled what i told you?
  • Nicolas S
    Nicolas S over 12 years
    Put 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
    Srikar Appalaraju over 12 years
    yes, 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
    Srikar Appalaraju over 12 years
    cool! didn't know this. Does this apply to [NSThread detachNewThreadSelector:@selector.... also?
  • Scott Forbes
    Scott Forbes over 12 years
    This 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
    Scott Forbes over 12 years
    Yes. Per the Apple docs, calling performSelectorInBackground:withObject: "is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters."
  • Sti
    Sti about 10 years
    Is there a difference between (unsigned long)NULL and 0 in this matter?
  • Jawad Al Shaikh
    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
    Ilya Denisov about 9 years
    Should I then use performSelectorOnMainThread to update UI with operation results or there is more consistent way to update UI with GCD?
  • OhadM
    OhadM almost 9 years
    Also, you can change the flag from DISPATCH_QUEUE_PRIORITY_DEFAULT to DISPATCH_QUEUE_PRIORITY_BACKGROUND