Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8345307
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 9, 20262026-06-09T06:38:08+00:00 2026-06-09T06:38:08+00:00

I have an NSManagedObjectContext declared like so: – (NSManagedObjectContext *) backgroundMOC { if (backgroundMOC

  • 0

I have an NSManagedObjectContext declared like so:

- (NSManagedObjectContext *) backgroundMOC {
    if (backgroundMOC != nil) {
        return backgroundMOC;
    }
    backgroundMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    return backgroundMOC;
}

Notice that it is declared with a private queue concurrency type, so its tasks should be run on a background thread. I have the following code:

-(void)testThreading
{
    /* ok */
    [self.backgroundMOC performBlock:^{
        assert(![NSThread isMainThread]); 
    }];

    /* CRASH */
    [self.backgroundMOC performBlockAndWait:^{
        assert(![NSThread isMainThread]); 
    }];
}

Why does calling performBlockAndWait execute the task on the main thread rather than background thread?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-09T06:38:09+00:00Added an answer on June 9, 2026 at 6:38 am

    Tossing in another answer, to try an explain why performBlockAndWait will always run in the calling thread.

    performBlock is completely asynchronous. It will always enqueue the block onto the queue of the receiving MOC, and then return immediately. Thus,

    [moc performBlock:^{
        // Foo
    }];
    [moc performBlock:^{
        // Bar
    }];
    

    will place two blocks on the queue for moc. They will always execute asynchronously. Some unknown thread will pull blocks off of the queue and execute them. In addition, those blocks are wrapped within their own autorelease pool, and also they will represent a complete Core Data user event (processPendingChanges).

    performBlockAndWait does NOT use the internal queue. It is a synchronous operation that executes in the context of the calling thread. Of course, it will wait until the current operations on the queue have been executed, and then that block will execute in the calling thread. This is documented (and reasserted in several WWDC presentations).

    Furthermore, performBockAndWait is re-entrant, so nested calls all happen right in that calling thread.

    The Core Data engineers have been very clear that the actual thread in which a queue-based MOC operation runs is not important. It’s the synchronization by using the performBlock* API that’s key.

    So, consider ‘performBlock’ as “This block is being placed on a queue, to be executed at some undetermined time, in some undetermined thread. The function will return to the caller as soon as it has been enqueued”

    performBlockAndWait is “This block will be executed at some undetermined time, in this exact same thread. The function will return after this code has completely executed (which will occur after the current queue associated with this MOC has drained).”

    EDIT

    Are you sure of “performBlockAndWait does NOT use the internal queue”?
    I think it does. The only difference is that performBlockAndWait will
    wait until the block’s completion. And what do you mean by calling
    thread? In my understanding, [moc performBlockAndWait] and [moc
    performBloc] both run on its private queue (background or main). The
    important concept here is moc owns the queue, not the other way
    around. Please correct me if I am wrong. – Philip007

    It is unfortunate that I phrased the answer as I did, because, taken by itself, it is incorrect. However, in the context of the original question it is correct. Specifically, when calling performBlockAndWait on a private queue, the block will execute on the thread that called the function – it will not be put on the queue and executed on the “private thread.”

    Now, before I even get into the details, I want to stress that depending on internal workings of libraries is very dangerous. All you should really care about is that you can never expect a specific thread to execute a block, except anything tied to the main thread. Thus, expecting a performBlockAndWait to not execute on the main thread is not advised because it will execute on the thread that called it.

    performBlockAndWait uses GCD, but it also has its own layer (e.g., to prevent deadlocks). If you look at the GCD code (which is open source), you can see how synchronous calls work – and in general they synchronize with the queue and invoke the block on the thread that called the function – unless the queue is the main queue or a global queue. Also, in the WWDC talks, the Core Data engineers stress the point that performBlockAndWait will run in the calling thread.

    So, when I say it does not use the internal queue, that does not mean it does not use the data structures at all. It must synchronize the call with the blocks already on the queue, and those submitted in other threads and other asynchronous calls. However, when calling performBlockAndWait it does not put the block on the queue… instead it synchronizes access and runs the submitted block on the thread that called the function.

    Now, SO is not a good forum for this, because it’s a bit more complex than that, especially w.r.t the main queue, and GCD global queues – but the latter is not important for Core Data.

    The main point is that when you call any performBlock* or GCD function, you should not expect it to run on any particular thread (except something tied to the main thread) because queues are not threads, and only the main queue will run blocks on a specific thread.

    When calling the core data performBlockAndWait the block will execute in the calling thread (but will be appropriately synchronized with everything submitted to the queue).

    I hope that makes sense, though it probably just caused more confusion.

    EDIT

    Furthermore, you can see the unspoken implications of this, in that the way in which performBlockAndWait provides re-entrant support breaks the FIFO ordering of blocks. As an example…

    [context performBlockAndWait:^{
        NSLog(@"One");
        [context performBlock:^{
            NSLog(@"Two");
        }];
        [context performBlockAndWait:^{
            NSLog(@"Three");
        }];
    }];
    

    Note that strict adherence to the FIFO guarantee of the queue would mean that the nested performBlockAndWait (“Three”) would run after the asynchronous block (“Two”) since it was submitted after the async block was submitted. However, that is not what happens, as it would be impossible… for the same reason a deadlock ensues with nested dispatch_sync calls. Just something to be aware of if using the synchronous version.

    In general, avoid sync versions whenever possible because dispatch_sync can cause a deadlock, and any re-entrant version, like performBlockAndWait will have to make some “bad” decision to support it… like having sync versions “jump” the queue.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

In iOS5, I have a NSManagedObjectContext which I create with a NSPrivateQueueConcurrencyType, like so:
hi :) I have a similarly issue like in Working with the same NSManagedObjectContext
I have one subclass of NSManagedObject like following and stored some instances by NSManagedObjectContext.
Example: The -save: method of NSManagedObjectContext is declared like this: - (BOOL)save:(NSError **)error Since
I have a simple objective c object NSManagedObjectContext * moc = nil Now I
I have the following code that currently clears all the objects in my NSManagedObjectContext:
I have a NSManagedObjectContext in which I have a number of subclasses of NSManagedObjects
I have a NSFetchedResultsController which is fetching objects from a NSManagedObjectContext . These objects
How can I copy an NSManagedObject from one NSManagedObjectContext to another? I have 2
Have a procedure which looks like Procedure TestProc(TVar1, TVar2 : variant); Begin TVar1 :=

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.