Use of NSManagedObjectContext under multiple threads in CoreData, nsmanagedobject

Source: Internet
Author: User

Use of NSManagedObjectContext under multiple threads in CoreData, nsmanagedobject
When I was at Google, I found two such blogs (,). The former introduces three NSManagedObjectContext designs under multiple threads, and the latter is the performance test conducted by the bloggers on these three designs. I will introduce them one by one: 1. persistentStoreCoordinator <-mainContext <-privateContext is the design I used in the project before, and it is also the most serious design for blocking UI threads. It has two contexts in total, one is mainContext used in the UI thread, the other is privateContext used in the child thread, and their relationship is privateContext. parentContext = mainContext, while mainContext is the Context connected to Disk. Therefore, in this design, every time the sub-thread privateContext performs the save operation, it pushes all database changes to its parent Context, in mainContext, note that the save operation of the sub-thread does not have any Disk IO operations. Then mainContext needs to execute a save operation in the UI thread to write data changes into the database. The save operation here is related to Disk IO, and it is in the main thread, therefore, this design is the most frustrating for UI threads. 2. The design of persistentStoreCoordinator <-backgroundContext <-mainContext <-privateContext is the first improvement design and is also a design method recommended by the old overseas bloggers. It has a total of three contexts, one is to connect persistentStoreCoordinator is also the underlying backgroundContext, the other is the mainContext of the UI thread, and the third is the privateContext of the subthread, the last two contexts have already been introduced in 1, so we will not detail them here. Their relationship is privateContext. parentContext = mainContext, mainContext. parentContext = backgroundContext. The following describes the specific workflow. In applications, if we have API operations, we will first initiate a sub-thread for API requests and perform database operations after obtaining the Response, this is to create a privateContext for data addition, deletion, modification, and query, and then call the save method of privateContext for storage, the save operation only pushes all data changes to its parent Context and mainContext. Then, mainContext continues to call the save method, push the data changes to its parent Context, that is, backgroundContext. Finally, call the save method of backgroundContext to store the data changes to the Disk database. In this process, the first two save operations are relatively time-consuming. The actual time-consuming operation is the save operation of the last backgroundContext, because it only has Disk IO operations. 3. persistentStoreCoordinator <-mainContext persistentStoreCoordinator <-privateContext the third design is the most intuitive one. Both mainContext and privateContext are connected to persistentStoreCoordinator. The workflow of this design is: first, add a notification named NSManagedObjectContextDidSaveNotification to ViewController, then create privateContext in the Child thread, perform data addition, deletion, modification, and query operations, and save it directly to the local database, in this case, ViewController calls back the previously registered NSManagedObjectContextDidSaveNotification callback method. In this method, the mergeChangesFromContextDidSaveNotification: notification method of mainContext is called to change all data to merge to mainContext, in this way, data synchronization is maintained between the two contexts. Most of the operations are privateContext operations in sub-threads, so this design is the least time-consuming design of the UI thread, but the cost is to write more mergeChanges methods. (Note: Once childContext calls the save method, its parentContext does not need any merge operations. CoreData automatically uploads data merge to parentContext.) summary: the first design is a failed design, which can be ignored at all. The second design is complicated and complicated, but it is the most convenient and the blocking time of the UI thread is relatively small. The third type of design is the one that blocks the UI at least, but this design operation is cumbersome. The application scenario is an application with a large amount of data, which is generally used in enterprise applications, so if you are not an enterprise application or an application with a large data volume, I recommend the second design. I wrote a Demo based on the second design. Some key code is attached below for your reference. Note: Before referring to the code, you may need to understand the concurrencyType of NSManagedObjectContext, there is also the difference between javasmblock and javasmblockandwait: methods. // This is the backgroundContext-(NSManagedObjectContext *) rootObjectContext {if (nil! = _ RootObjectContext) {return _ rootObjectContext;} NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator]; if (coordinator! = Nil) {_ rootObjectContext = [[NSManagedObjectContext alloc] handler: Handler]; [_ rootObjectContext handler: coordinator];} return _ rootObjectContext;} // This is mainContext-(handler *) managedObjectContext {if (nil! = _ ManagedObjectContext) {return _ managedObjectContext;} _ managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: callback]; _ managedObjectContext. parentContext = [self rootObjectContext]; return _ managedObjectContext; // _ managedObjectContext = [[NSManagedObjectContext alloc] init]; // _ managedObjectContext. persistentStoreCoordinator = [self persistentSto ReCoordinator]; // return _ managedObjectContext;} // saveContext method in AppDelegate. call this method every time privateContext calls the save method successfully-(void) saveContextWithWait :( BOOL) needWait {response * response = [self managedObjectContext]; response * rootObjectContext = [self rootObjectContext]; if (nil = managedObjectContext) {return;} if ([callback hasChanges]) {NSLog (@ "Main context need to save"); [managedObjectContext extends mblockandwait: ^ {NSError * error = nil; if (! [ManagedObjectContext save: & error]) {NSLog (@ "Save main context failed and error is % @", error) ;}}];} if (nil = rootObjectContext) {return;} RootContextSave rootContextSave = ^ {NSError * error = nil; if (! [_ RootObjectContext save: & error]) {NSLog (@ "Save root context failed and error is % @", error) ;}}; if ([rootObjectContext hasChanges]) {NSLog (@ "Root context need to save"); if (needWait) {[rootObjectContext extends mblockandwait: rootContextSave];} else {[rootObjectContext extends mblock: rootContextSave];} // This is a pseudo API method and is only used by Demo + (void) Consumer :( NSManagedObjectContext *) mainContext completionBlock :( CompletionBlock) block {NSManagedObjectContext * workContext = [NSManagedObjectContext consumer: mainContext]; [workContext worker mblock: ^ {Employee * employee = [NSEntityDescription Employee: @ "employee" inManagedObjectContext: workContext]; [Employee setRandomData]; NSError * error = nil; if ([workContext save: & error]) {block (YES, nil, nil);} else {NSLog (@ "Save employee failed and error is % @", error); block (NO, nil, @ "Get emploree failed") ;}}] ;}// this is the Category of callback @ implementation NSManagedObjectContext (GenerateContext) + (NSManagedObjectContext *) Principal :( NSManagedObjectContext *) parentContext {NSManagedObjectContext * privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; privateContext. parentContext = parentContext; return privateContext;} + (optional *) Principal :( NSManagedObjectContext *) mainContext {NSManagedObjectContext * privateContext = [[NSManagedObjectContext alloc] init]; privateContext. persistentStoreCoordinator = mainContext. persistentStoreCoordinator; return privateContext;} @ end // This is the Code related to API operations and UI refreshing in ViewController, from refreshData method-(void) refreshData {[EmployeeTool getEmployeesWithMainContext: [self mainContext] completionBlock: ^ (BOOL operationSuccess, id responseObject, NSString * errorMessage) {if ([NSThread isMainThread]) {NSLog (@ "Handle result is main thread "); [self handleResult: operationSuccess];} else {NSLog (@ "Handle result is other thread"); [self defined mselec1_mainthread: @ selector (handleResult :) withObject: [NSNumber numberWithBool: operationSuccess] waitUntilDone: YES] ;}}-(void) handleResult :( BOOL) operationSuccess {if (operationSuccess) {NSLog (@ "Operation success "); [self saveContext];} [self. refreshControl endRefreshing];}-(void) saveContext {WMAppDelegate * appDelegate = (WMAppDelegate *) [UIApplication sharedApplication]. delegate; [appDelegate saveContextWithWait: NO];}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.