NSOperation and NSOperationQueue workflow vs main thread

I need to perform a series of database load and write operations in my application. I am using NSOperation and NSOperationQueue for this.

This is the application script:

  • Get all zip codes from place.
  • For each zip code, select all homes.
  • For each house, select residents.

As I said, I defined NSOperation for each task. In the first case (Task1) I send a request to the server to get all the zip codes. The delegate at NSOperation will receive the data. This data is then written to the database. The database operation is defined in another class. From the NSOperation class NSOperation I make a call to the write function defined in the database class.

My question is: is there a database write operation in the main thread or in the background thread? Since I called it in NSOperation , I expected it to work in another thread (Not MainThread) as NSOperation . Can someone explain this scenario by dealing with NSOperation and NSOperationQueue .

+74
multithreading ios objective-c nsoperation nsoperationqueue
Oct 24 '13 at 14:49
source share
6 answers

My question is, is there a database write operation in the main thread or in the background thread?

If you create an NSOperationQueue from scratch, as in:

 NSOperationQueue *myQueue = [[NSOperationQueue alloc] init]; 

It will be in the background thread:

Operational queues typically provide threads used to start their operation. In OS X v10.6 and later, operational queues use the libdispatch library (also known as Grand Central Dispatch) to run their operations. As a result, operations are always performed in a separate thread , regardless of whether they are designated as parallel or non-competitive operations

If you are not using mainQueue :

 NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; 

You can also see the code as follows:

 NSOperationQueue *myQueue = [[NSOperationQueue alloc] init]; [myQueue addOperationWithBlock:^{ // Background work [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // Main thread work (UI usually) }]; }]; 

And the GCD version:

 dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { // Background work dispatch_async(dispatch_get_main_queue(), ^(void) { // Main thread work (UI usually) }); }); 

NSOperationQueue gives you more precise control over what you want to do. You can create dependencies between two operations (loading and saving to the database). To transfer data between one block and another, you can assume, for example, that NSData will come from the server like this:

 __block NSData *dataFromServer = nil; NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation *weakDownloadOperation = downloadOperation; [weakDownloadOperation addExecutionBlock:^{ // Download your stuff // Finally put it on the right place: dataFromServer = .... }]; NSBlockOperation *saveToDataBaseOperation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation *weakSaveToDataBaseOperation = saveToDataBaseOperation; [weakSaveToDataBaseOperation addExecutionBlock:^{ // Work with your NSData instance // Save your stuff }]; [saveToDataBaseOperation addDependency:downloadOperation]; [myQueue addOperation:saveToDataBaseOperation]; [myQueue addOperation:downloadOperation]; 

Edit: Why I use the __weak link for Operations can be found here . But in a nutshell, save cycles should be avoided.

+158
Nov 02
source share

If you want to perform a database write operation in a background thread, you need to create an NSManagedObjectContext for this stream.

You can create the NSManagedObjectContext background in the start method of your corresponding NSOperation subclass.

Check out Apple docs for Concurrency with master data.

You can also create an NSManagedObjectContext that executes queries in its background thread by creating it using NSPrivateQueueConcurrencyType and executing the queries inside your performBlock: method.

+14
Oct 30 '13 at 9:31 on
source share

The NSOperation execution line depends on the NSOperationQueue where you added the operation. See this expression in your code -

 [[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class 

All this assumes that you have not yet executed the thread in the main NSOperation method, which is the actual monster in which the working instructions (which are expected) are written.

However, in the case of simultaneous operations, the scenario is different. A queue can spawn a thread for each concurrent operation. Although this is not guaranteed, and it depends on the system resources and the requirements of the work resource at that moment in the system. You can control the concurrency of the work queue with the maxConcurrentOperationCount property.

EDIT -

I found your question interesting and made the analysis / log itself. I have an NSOperationQueue created in the main thread, like this -

 self.queueSendMessageOperation = [[[NSOperationQueue alloc] init] autorelease]; NSLog(@"Operation queue creation. current thread = %@ \n main thread = %@", [NSThread currentThread], [NSThread mainThread]); self.queueSendMessageOperation.maxConcurrentOperationCount = 1; // restrict concurrency 

And then I continued to create NSOperation and added it using addOperation. In the main method of this operation, when I checked the current thread,

 NSLog(@"Operation obj = %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]); 

it was not the main stream. And I found that the current stream object is not an object of the main stream.

Thus, user queuing in the main thread (without concurrency among its operations) does not necessarily mean that the operations will be performed sequentially along the main thread.

+9
Oct 30 '13 at 5:07 on
source share

From NSOperationQueue

IOS 4 and later operational queues use the Grand Central Dispatch feature to perform operations. Prior to iOS 4, they create separate threads for non-competitive operations and start parallel operations from the current thread.

So,

 [NSOperationQueue mainQueue] // added operations execute on main thread [NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread 

In your case, you can create your own "database thread" by subclassing NSThread and sending messages to it using performSelector:onThread:

+8
Nov 01 '13 at 13:32
source share

Document Summary - operations are always executed on a separate thread (post iOS 4 implies GCD operational queues).

This is trivial to verify that it really works on the main thread:

 NSLog(@"main thread? %@", [NSThread isMainThread] ? @"YES" : @"NO"); 

When starting in a thread, it is trivial to use GCD / libdispatch to start something in the main thread, whether it is the main data, the user interface, or other code needed to run in the main thread:

 dispatch_async(dispatch_get_main_queue(), ^{ // this is now running on the main thread }); 
+1
Nov 02 '13 at 19:52
source share

If you are doing any non-trivial threads, you should use FMDatabaseQueue .

-2
Oct 30 '13 at 2:10
source share



All Articles