in Google, I found such a blog of two foreigners (,). The former is the introduction of Nsmanagedobjectcontext in the multi-threaded three kinds of design, the latter is the blogger on these three design performance test. Here's what I'll cover:1. Persistentstorecoordinator<-maincontext<-privatecontextThis design is what I used to do in my project, and it's one of the most serious blocking UI threads. It has a total of two context, one is maincontext used in the UI thread, one is the privatecontext used in the child thread, their relationship is Privatecontext.parentcontext = Maincontext, And Maincontext is a context that is connected to disk, so this design, whenever the child thread privatecontext The save operation, it will push the database all changes to its parent context, that is, Maincontext , note that the save operation of the child thread does not have any action on disk IO at this point. The Maincontext then performs a save operation on the UI thread to actually write data changes into the database, where the save operation is related to disk IO and is in the main thread, so this design is the most blocking of the UI thread. 2. Persistentstorecoordinator<-backgroundcontext<-maincontext<-privatecontextThis design is the first kind of improvement design, is also the above-mentioned foreigner blogger recommended a design method. It has a total of three context, one is the connection Persistentstorecoordinator is also the lowest backgroundcontext, the second is the UI thread Maincontext, three is the privatecontext of the child thread, The latter two context have been introduced in 1, here is no longer specifically described, their relationship is Privatecontext.parentcontext = maincontext, Maincontext.parentcontext = Backgroundcontext. Let's talk about its specific work flow. in the application, if we have API operation, first we will make a sub-thread API request, after getting response to do database operation, this is we want to create a privatecontext to do data deletion and modification, and then call Privatecontext Save method, where the save operation simply push up all data changes to its parent context, which is maincontext, and then Maincontext continue to call the Save method, Push up the data changes to its parent context, which is backgroundcontext, and finally call Backgroundcontext's Save method to actually store the data changes in the disk database, in this process, The first two save operations are relatively time-consuming, and the really time-consuming operation is the last Backgroundcontext save operation, because only it has disk IO operations. 3. Persistentstorecoordinator<-maincontextPersistentstorecoordinator<-privatecontextThe third design is the most intuitive design, whether it is Maincontext or privatecontext are connected persistentstorecoordinator. The workflow for this design is:first, in Viewcontroller, you add a notification named Nsmanagedobjectcontextdidsavenotification, and then create the Privatecontext in the sub-thread, make data additions and deletions, direct save to the local database, The callback method of the previously registered nsmanagedobjectcontextdidsavenotification is then recalled in Viewcontroller, In this method, call Maincontext's Mergechangesfromcontextdidsavenotification:notification method, merge all the data changes into Maincontext, This keeps the data synchronized in the two context. Since most of the operations are privatecontext in a child thread, this design is the least time consuming design for the UI thread, but it costs more to write mergechanges methods. (Note: The first two parent,child context, once Childcontext calls the Save method, its parentcontext without any merge operation, CoreData automatically merge data into Parentcontext)Summary:The first design is the failure of the design, can not be considered, the second design is more complex and cumbersome, but it is the most convenient and the UI thread blocking time is also relatively small. The third design is one of the least blocking UI, but this kind of design operation is more cumbersome, the application is a large amount of data applications, generally used in enterprise applications, so if you are not an enterprise-class application or not a large number of applications, I still recommend the second design. I wrote a demo based on the second design, with some key codes attached below for your reference:Note: Before referencing the code, you may want to know something about Nsmanagedobjectcontext's concurrencytype, and there is Performblock and performblockandwait: The difference between the methods. //This is appdelegate Backgroundcontext-(Nsmanagedobjectcontext *) Rootobjectcontext {if (nil! = _rootobjectcontext) {return _ Rootobjectcontext; } nspersistentstorecoordinator *coordinator = [self persistentstorecoordinator]; if (Coordinator! = nil) {_rootobjectcontext = [[Nsmanagedobjectcontext alloc] Initwithconcurrencytype: Nsprivatequeueconcurrencytype]; [_rootobjectcontext Setpersistentstorecoordinator:coordinator]; } return _rootobjectcontext; }//this is maincontext. -(Nsmanagedobjectcontext *) Managedobjectcontext {if (nil! = _managedobjectcontext) {return _managedobjectcontext;} _m Anagedobjectcontext = [[Nsmanagedobjectcontext alloc] initwithconcurrencytype:nsmainqueueconcurrencytype]; _managedobjectcontext.parentcontext = [self rootobjectcontext]; return _managedobjectcontext; _managedobjectcontext = [[Nsmanagedobjectcontext alloc] init]; _managedobjectcontext.persistentstorecoordinator = [self persistentstorecoordinator]; return _managedobjectcontext; }Savecontext method in Appdelegate, each time the Privatecontext call to the Save method succeeds, it calls this method-(void) savecontextwithwait: (BOOL) needwait { Nsmanagedobjectcontext *managedobjectcontext = [self managedobjectcontext]; Nsmanagedobjectcontext *rootobjectcontext = [self rootobjectcontext]; if (nil = = Managedobjectcontext) {return;} if ([Managedobjectcontext haschanges]) {NSLog (@ "Main context need to save"); [Managedobjectcontext performblockandwait:^{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 Performblock Andwait:rootcontextsave]; } else {[Rootobjectcontext performblock:rootcontextsave];}} }//This is a pseudo-API method , only for demo use + (void) Getemployeeswithmaincontext: (Nsmanagedobjectcontext *) Maincontext Completionblock: ( Completionblock) Block {nsmanagedobjectcontext *workcontext = [Nsmanagedobjectcontext Generateprivatecontextwithparent:maincontext]; [Workcontext performblock:^{Employee *employee = [nsentitydescription insertnewobjectforentityforname:@ ' 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 nsmanagedobj. Ectcontext category @implementation Nsmanagedobjectcontext (generatecontext) + (Nsmanagedobjectcontext *) Generateprivatecontextwithparent: (Nsmanagedobjectcontext *) Parentcontext {Nsmanagedobjectcontext *privateContext = [[Nsmanagedobjectcontext alloc] initwithconcurrencytype:nsprivatequeueconcurrencytype]; Privatecontext.parentcontext = Parentcontext; return privatecontext; } + (Nsmanagedobjectcontext *) Generatestraightprivatecontextwithparent: (Nsmanagedobjectcontext *) MainContext { Nsmanagedobjectcontext *privatecontext = [[Nsmanagedobjectcontext alloc] init]; Privatecontext.persistentstorecoordinator = Maincontext.persistentstorecoordinator; return privatecontext; } @end //This is the code for API operation and UI refresh in Viewcontroller, from the 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 the other thread"); [Self Performselectoronmainthread: @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]; }
CoreData the use of Nsmanagedobjectcontext under multi-threading