Understanding coredata – using advanced

Time:2020-2-13
This article belongs to the original of “Jianshu Liu Xiaozhuang”. Please indicate:

< Jianshu Liu Xiaozhuang > http://www.jianshu.com/p/a4710356244d


The previous two articles are more theoretical, more text expression, but are dry goods! When learning, we should understand the theoretical knowledge first, so as to better help the later understanding.

In this article, we will talk aboutCoreDataSome complex operations of, these operations will involve paging query, fuzzy query, batch processing and other advanced operations.

Through these operations, it can be better usedCoreDataUpgradeCoreDataPerformance. There will be a lot of sample code in this article, which is more helpful to understand in the way of code.
I hope you will read the article patiently.

If there is any omission or mistake in the article, please put forward it in time, thank you! A kind of


Understanding coredata - using advanced

NSPredicate

Summary

stayiOSIn the development process, many requirements need to use filter conditions. For example, to filter the objects stored in a collection object, you canFoundationUnder the frameworkNSPredicateClass to perform this operation.

CoreDataYou can set theNSFetchRequestClasspredicateProperty to set aNSPredicateType as a filter. By setting this filter condition, only the managed objects that meet the filter condition can be obtained, and all managed objects will not be loaded into memory. This can save memory and speed up search. Design a good oneNSPredicateCan be optimizedCoreDataSearch performance.

grammar

NSPredicateIt’s more natural than naturalSQLiteThere are a lot of fixed grammar, it seems more clear and understandable. For example, the following conditions need to be found:Over 30 years oldAndIncluding 30 years oldConditions.

[NSPredicate predicateWithFormat:@"age >= 30"]
Filter collection objects

Can passNSPredicateYesiOSThe collection object in performs filtering operations, which can beNSArrayNSSetAnd its subclasses.

To immutable arrayNSArrayAfter filtering, aNSArrayType, which stores the objects that meet the filter criteria.

NSArray *results = [array filteredArrayUsingPredicate:predicate]

To variable arrayNSMutableArrayAfter filtering, the objects stored in the original collection objects will be changed directly and the unqualified objects will be deleted.

[arrayM filterUsingPredicate:predicate]
Composite filter conditions

Predicate can not only filter simple conditions, but also filter complex conditions and set compound filter conditions.

[NSPredicate predicateWithFormat:@"(age < 25) AND (firstName = XiaoZhuang)"]

Of course, it can also beNSCompoundPredicateObject to set the composite filter conditions. The returned result is aNSPredicateSubclassesNSCompoundPredicateObject.

[[NSCompoundPredicate alloc] initWithType:NSAndPredicateType subpredicates:@[predicate1, predicate2]]

enumNSCompoundPredicateTypeParameters, you can set three composite conditions, enumeration value is very intuitive and easy to understand.

  • NSNotPredicateType
  • NSAndPredicateType
  • NSOrPredicateType
Basic grammar

Here are someNSPredicateIt seems to be very easy to understand,More complicated usage can be found in Apple’s official API

grammar Effect
== Judge whether it is equal
>= Greater than or equal to
<= Less than or equal to
> greater than
< less than
!= Not equal to
AND or & & and
OR or II or
NOT or! wrong
regular expression

NSPredicateYou can also useregular expression , you can complete some complex requirements through regular expressions, which makes the predicate more powerful. For example, the following is aRegular expression of mobile phone number verification

NSString *mobile = @"^1(3[0-9]|5[0-35-9]|8[025-9])\d{8}$";
NSPredicate *regexmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", mobile];
Fuzzy query

NSPredicateSupport fuzzy query of data, for example, use wildcard toMatch results with lxzSpecificCoreDataThe use of in is discussed below.

[NSPredicate predicateWithFormat:@"name LIKE %@", @"*lxz*"]
keyPath

NSPredicateWhen creating query criteria, it also supports setting thekeyPathThat is to saySet deeper matched targets。 For example, the following settingsemployeeOfnameProperty is the search condition, which is set with point syntaxkeyPath

[NSPredicate predicateWithFormat:@"employee.name = %@", @"lxz"]

Set query criteria

In the previous article, execute the followingMOCOffetchRequestMethod, usually aNSFetchRequestType. thisrequestParameters can do some setting operations, so that you can get the specified data with better performance.

- (nullable NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error;

NSFetchRequest

In executionfetchBefore operation, you canNSFetchRequestSet some parameters, including predicate, sorting and other conditions. Here are some basic settings.

  • To set which entity to look for, from the perspective of database, is to look up which table throughfetchRequestWithEntityName:Or initialize the method to specify the table name.
  • adoptNSPredicateType, you can set the search criteria. This attribute is used most in development.NSPredicateCan include fixed format conditions as well asregular expression
  • adoptsortDescriptorsProperty, you can set the sorting method to get the result array. This property is an array type, that isMultiple sorting conditions can be set。 (but pay attention not to conflict with the conditions)
  • adoptfetchOffsetProperty settings are obtained from the first few results of the query through thefetchLimitProperty to set how many to get at a time. Mainly usedPaging query, later.

MOCimplementfetchAfter the operation, the result obtained is stored in the form of an array, in which the managed object is stored.NSFetchRequestParameters providedresultType, parameter type is an enumeration type. With this parameter, you can set the executionfetchThe data type returned after the operation.

  • NSManagedObjectResultType: return value isNSManagedObjectThis is the default option.
  • NSManagedObjectIDResultType: ReturnNSManagedObjectIDObject of type, that isNSManagedObjectOfID, which takes up less memory.MOCCan passNSManagedObjectIDObject gets the corresponding managed object and can be cachedNSManagedObjectIDParameter to save memory consumption.
  • NSDictionaryResultType: returns a dictionary type object.
  • NSCountResultType: returns thecountValue, which occurs at the database level and does not need to load data into memory.

Set acquisition conditions

//Establish the request object to get data and indicate the operation employee table
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

//Set request conditions, filter out the required data through the set conditions
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", @"lxz"];
request.predicate = predicate;

//Set the sorting method of request results. You can set one or a group of sorting methods. Finally, add all sorting methods to the sorting array
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];
//The operation of nssortdescriptor is completed at SQLite level, and the object will not be loaded into memory, so the memory consumption is very small
request.sortDescriptors = @[sort];

//Execute the get request operation. The obtained managed object will be stored in an array and returned
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Employee Name : %@, Height : %@, Brithday : %@", obj.name, obj.height, obj.brithday);
}];

//Error handling
if (error) {
    NSLog(@"CoreData Fetch Data Error : %@", error);
}

Set up hereNSFetchRequestObject, set the searchEmployeeIn the tablenamebylxzAnd useheightvalueAscending orderIn this way.

Have entity relationship

The relationship between entities in a model file can be set, as mentioned in the previous article. Entity relationship is divided intoRight oneorMore on, you can also set whether or notBidirectional correlation

The entities shown here are simpleTo OneAnd the following will show the difference and comparison of setting whether two-way association or not.

Insert entity

//Creates a managed object and associates it to the specified MOC
Employee *zsEmployee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:context];
zsEmployee.name = @"zhangsan";
zsEmployee.height = @1.9f;
zsEmployee.brithday = [NSDate date];

Employee *lsEmployee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:context];
lsEmployee.name = @"lisi";
lsEmployee.height = @1.7f;
lsEmployee.brithday = [NSDate date];

Department *iosDepartment = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:context];
iosDepartment.departName = @"iOS";
iosDepartment.createDate = [NSDate date];
iosDepartment.employee = zsEmployee;

Department *androidDepartment = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:context];
androidDepartment.departName = @"android";
androidDepartment.createDate = [NSDate date];
androidDepartment.employee = lsEmployee;

//Perform storage operations
NSError *error = nil;
if (context.hasChanges) {
    [context save:&error];
}

//Error handling
if (error) {
    NSLog(@"Association Table Add Data Error : %@", error);
}

Four entities are created above, and theEmployeeAre related toDepartmentOn, pass after completing the associated operationMOCStore locally.

You can see that all the above managed objects are created using theNSEntityDescriptionOfinsertMethod creation,And relate to the context。 Now I want to ask, I can directly use the traditionalinitMethod creation?

Crumbling😱!MOC needs to be specified when creating managed objects, dynamically generated at run timesetgetMethod. But directly throughinitMethod initialization object. The system does not know that it needs to be generated by the system itselfsetgetMethod, and the system does not know which one to correspond toMOC, which causes the method to crash if it is not implemented. Therefore, there are often errors in development, such as the following crash information:


-[Employee setName:]: unrecognized selector sent to instance 0x7fa665900f60

Bidirectional correlation

Mentioned in the previous articleBidirectional correlationThe concept of settingRelationshipTimeInverseWhether it is empty. Below isEmployeeandDepartmentIn the database, setinverseAnd no settingsinverseThe two kinds of data storage can clearly compare the differences of setting up two-way Association.
Test code or insert entity code with the above, just changeinverseOptions.

Set bidirectional association

Understanding coredata - using advanced

Understanding coredata - using advanced

No two-way Association set

Understanding coredata - using advanced

Understanding coredata - using advanced

As can be seen from the figure, there is no bi-directional Association entity,DepartmentRelationEmployeeAfter the attribute is stored,DepartmentThe relationship in the table exists, butEmployeeThe relationship in the table is still empty. However, the entity with two-way association is set in theDepartmentRelationEmployeeAfter the attribute is stored,EmployeeAnd are automatically set in the tableDepartmentRelationship.

The relationship of two-way association is not only reflected in the database, but also in the process of program running. For two-way Association parties, the relationship between one party’s Association attributes will also change after the relationship between the other party’s Association attributes is set. Print the associated properties with the following code, and the result is the same as the change of the above database.

NSLog(@"Department : %@, Employee : %@", androidDepartment.employee, lsEmployee.department);

Query operation

//Create the request object to get the data and indicate the operation department table
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Department"];

//Set the request condition, and set the name of employee as the request condition. The advantage of nspredict is that you can set the keypath condition
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"employee.name = %@", @"lxz"];
request.predicate = predicate;

//Perform a find operation
NSError *error = nil;
NSArray<Department *> *departments = [context executeFetchRequest:request error:&error];
[departments enumerateObjectsUsingBlock:^(Department * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Department Search Result DepartName : %@, employee name : %@", obj.departName, obj.employee.name);
}];

//Error handling
if (error) {
    NSLog(@"Department Search Error : %@", error);
}

lookupDepartmentEntity and print entity content. Just like the above two-way relationship, entities with related relationships will alsoFind other entities associated with it, and the entities found are all relatedMOC.

Paging query

When getting data from the local store, you canSpecify which to get fromAs well asHow many data are obtained in this queryIn combinationPaging query。 Of course, the two can be used separately according to the needsAPI

This requirement is very common in actual development, such asTableViewMiddle, pull up to load data, load each time20 articleData, you can use paging query easily.

//Create the request object to get the data and indicate the operation employee table
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

//Set the search starting point, which is obtained from the sixth search result
request.fetchOffset = 6;

//Set paging to get six managed objects per request
request.fetchLimit = 6;

//Set the sorting rules, and set the height ascending sorting here
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"height" ascending:YES];
request.sortDescriptors = @[descriptor];

//Perform query operation
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Page Search Result Name : %@, height : %@", obj.name, obj.height);
}];

//Error handling
if (error) {
    NSLog(@"Page Search Data Error : %@", error);
}

The top one is in ascending order of height,Paging acquisitionExamples of search results. lookupEmployeeThe entity in the table, the result isheightThe fields are sorted in ascending order, and the search starts from the sixth result, and the number of acquired fields is also set to six.

Fuzzy query

Sometimes needGet has some of the same characteristicsThe result of the queryFuzzy matching。 stayCoreDataWhen performing a fuzzy match, you can use theNSPredicateDo this.

//Create a request object to get data, and set to operate on the employee table
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

//Create fuzzy query conditions. The query with wildcard is set here. The query condition is that the result contains lxz
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE %@", @"*lxz*"];
request.predicate = predicate;

//Perform query operation
NSError *error = nil;
NSArray<Employee *> *employees = [context executeFetchRequest:request error:&error];
[employees enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Fuzzy Search Result Name : %@, height : %@", obj.name, obj.height);
}];

//Error handling
if (error) {
    NSLog(@"Fuzzy Search Data Error : %@", error);
}

Above is the use ofwildcardByFuzzy queryNSPredicateVarious forms of fuzzy query are supported. Here are some simple matching methods. Fuzzy query conditionsInsensitive to case, so the query criteria can be case sensitive.

  • Start with lxz

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@”name BEGINSWITH %@”, @”lxz”];

  • Ending with lxz

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@”name ENDSWITH %@”, @”lxz”];

  • It contains lxz

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@”name contains %@”, @”lxz”];

  • Query condition result contains lxz

    NSPredicate predicate = [NSPredicate predicateWithFormat:@”name LIKE %@”, @”lxz*”];

Load request template

As mentioned in the previous articleSet request template in model file, that is to say.xcdatamodeldFiles, settingFetch Requests, you can use the correspondingNSManagedObjectModelGet the set template.

... omit context creation steps
//Get the managed object model corresponding to the model file through MOC
NSManagedObjectModel *model = context.persistentStoreCoordinator.managedObjectModel;
//Get the request object through the template name set in the. Xcdatamodel file
NSFetchRequest *fetchRequest = [model fetchRequestTemplateForName:@"EmployeeFR"];

//Request data. The following operations are the same as normal requests
NSError *error = nil;
NSArray<Employee *> *dataList = [context executeFetchRequest:fetchRequest error:&error];
[dataList enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"Employee.count = %ld, Employee.height = %f", dataList.count, [obj.height floatValue]);
}];

//Error handling
if (error) {
    NSLog(@"Execute Fetch Request Error : %@", error);
}

Get result count value

In the development process, it is sometimes necessary to obtain only the required dataCountValue, that is, after performing the get operationNumber of objects stored in the array。 Meet this demand, if it is the same as beforeMOCExecute the get operation, get the array and then get theCountThis wayIt consumes a lot of memory

For this demand, apple provides two common ways to obtain thisCountValue. Both of these operations are completed in the database,No need to load managed objects into memory, the memory overhead is also very small.

Method 1, set resulttype

//Set filter conditions. You can set your own filter conditions according to your needs
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"height < 2"];
//Create the request object and indicate the operation employee table
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
fetchRequest.predicate = predicate;
//This step is the key. Set the return result type to count and the return result to nsnumber
fetchRequest.resultType = NSCountResultType;

//When performing query operation, the returned result is still an array. There is only one object in the array, which is the calculated count value
NSError *error = nil;
NSArray *dataList = [context executeFetchRequest:fetchRequest error:&error];
NSInteger count = [dataList.firstObject integerValue];
NSLog(@"fetch request result Employee.count = %ld", count);

//Error handling
if (error) {
    NSLog(@"fetch request result error : %@", error);
}

Method 1Set inNSFetchRequestObjectresultTypebyNSCountResultType, get the result’sCountValue. This enumeration value was mentioned in the previous article, exceptCountParameter, three other parameters can be set.

Method 2, using the method provided by MOC

//Set filter conditions
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"height < 2"];
//Create request object indicating operation of employee table
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
fetchRequest.predicate = predicate;

//By calling the countforfetchrequest: error: method of MOC, the request result count value is obtained, and the returned result is the nsuinteger type variable directly
NSError *error = nil;
NSUInteger count = [context countForFetchRequest:fetchRequest error:&error];
NSLog(@"fetch request result count is : %ld", count);

//Error handling
if (error) {
    NSLog(@"fetch request result error : %@", error);
}

MOCProvides specialized access to request resultsCountValue method, through which you can directly return aNSUIntegerTypeCountValue, which is more convenient to use than the above method. The others are the same.

Bit operation

If there is demand, it is rightEmployeeTable for all managed objectsheightattributeSum of computation。 In the case of large amount of data, it is very memory consuming to load all managed objects into memory. Even batch loading is time-consuming.

CoreDataFor such needs, it providesBit operationFunction.MOCWhen executing the request, it supports bit operation on the data. This operation is stillComplete at database levelThe memory usage is very small.

//Create request object indicating operation of employee table
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
//Set the return value to dictionary type, so that the result can be retrieved through the name set. This step is necessary
fetchRequest.resultType = NSDictionaryResultType;

//Create a description object
NSExpressionDescription *expressionDes = [[NSExpressionDescription alloc] init];
//Set the name of the description object. The final result needs to use the name as the key to get the result
expressionDes.name = @"sumOperatin";
//Set the return value type according to the operation result
expressionDes.expressionResultType = NSFloatAttributeType;

//Create a specific description object to describe what operations are performed on that attribute (there are many types of operations that can be performed. Here, sum operations are performed on the height attribute)
NSExpression *expression = [NSExpression expressionForFunction:@"sum:" arguments:@[[NSExpression expressionForKeyPath:@"height"]]];
//Only one specific description object can be mapped
expressionDes.expression = expression;
//Set the description object for the request object. Here is an array type, that is, multiple description objects can be set
fetchRequest.propertiesToFetch = @[expressionDes];

//When executing a request, the return value is an array. There is only one element in the array, which is the dictionary storing the calculation results
NSError *error = nil;
NSArray *resultArr = [context executeFetchRequest:fetchRequest error:&error];
//Use the name value set above as the key of the request result to retrieve the calculation result
NSNumber *number = resultArr.firstObject[@"sumOperatin"];
NSLog(@"fetch request result is %f", [number floatValue]);

//Error handling
if (error) {
    NSLog(@"fetch request result error : %@", error);
}
results of enforcement

Understanding coredata - using advanced

As you can see from the execution results,MOCFor all found managed objectsheightProperty, andPut results in dictionaryReturn. Bit operation is mainly throughNSFetchRequestObjectpropertiesToFetchProperty setting. This property can be used to set multiple description objects. Finally, differentnameTreat askeyJust take out the results.

NSExpressionClass can describe a variety of operations, which can beNSExpression.hIn the comment part of the file, I see all the supported operation types. I have seen about 20 kinds of operations. And besides the topNSExpressionMethod called, which also supportsPoint grammarFor example, the following example.

[NSExpression expressionWithFormat:@"@sum.height"];

Batch processing

in useCoreDataPreviously, I also discussed with my colleagues in the company, assuming that we meet the needsMassive data processingWhat to do when it’s time.CoreDataThe flexibility to process large amounts of data is certainly not as goodSQLiteAt this time, you need to use other methods to optimize data processing.Although this is rare on the mobile end, but this should be considered in the design of persistence layer.

When data processing is needed,CoreDataData needs to be transferred firstLoad into memory, and then the data can be processed. In this way, for a large number of data, it is very memory consuming to load them into memory, and it is easy to cause crash. If encounteredChange a field of all dataSuch a simple requirement requires that all related managed objects be loaded into memory, and then changed and saved.

For the above questions,CoreDatastayiOS8LaunchedBatch update APIThrough thisAPICan be directly inDatabase layer 1Complete the update operation, andNo need to load data into memory。 In addition to the batch update operation, theiOS9China also launchedBatch delete APIIt is also an operation completed at the database level. About batchAPIMany of them areiOS8iOS9Come out, when in useNeed to pay attention to version compatibility

But there is a problem. There are two problems: batch update and batch deleteAPIAll areOperate the database directly, which will causeMOCCaching and local persistenceData out of syncThe problem. thereforeManaged objects stored in the affected MOC need to be refreshed manuallyMakeMOCAnd local integration. Suppose you useNSFetchedResultsControllerIn order to ensure the unity of interface and data, this step of update operation needs to be done more.

Batch update

//Create a batch update object and indicate the operation employee table.
NSBatchUpdateRequest *updateRequest = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:@"Employee"];
//Set the return value type. By default, nothing is returned (nsstatusonlyresulttype). Here, set the return object count value that has changed
updateRequest.resultType = NSUpdatedObjectsCountResultType;
//Set dictionary for changed fields
updateRequest.propertiesToUpdate = @{@"height" : [NSNumber numberWithFloat:5.f]};

//After the request is executed, the return value is a specific result object, and the returned result is obtained through the property of result. This API of MOC is from IOS 8, so you need to pay attention to version compatibility.
NSError *error = nil;
NSBatchUpdateResult *result = [context executeRequest:updateRequest error:&error];
NSLog(@"batch update count is %ld", [result.result integerValue]);

//Error handling
if (error) {
    NSLog(@"batch update request result error : %@", error);
}

//Update managed objects in MOC to synchronize MOC and local persistent area data
[context refreshAllObjects];

Above pairEmployeeAll managed objects in the tableheightThe value is updated in batch. When updating, set thepropertiesToUpdateDictionary to control the update fields and the updated values. The format isField name: new value。 By setting thepredicateProperty, set a predicate object toControl affected objects

You can also do the same batch operation for multiple storage areas (databases) by settingIts parent classOfaffectedStoresProperty, the type is an array, which can contain the operations of affected storage areas and multiple storage areasSame for bulk deletion

MOCWhen executing the request method, it is found that the method name is not the same. What is executed isexecuteRequest: error:Method, this method is fromiOS8After that. The parameter passed in by the method isNSBatchUpdateRequestClass, which does not inherit fromNSFetchRequestClass, but directly inherited fromNSPersistentStoreRequest, andNSFetchRequestIt’s a level relationship.

Batch deletion

//Create the request object and indicate the operation on the employee table
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
//Set the filter condition through the predicate, and set the condition to height less than 1.7
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"height < %f", 1.7f];
fetchRequest.predicate = predicate;

//Create a batch deletion request and initialize it with the request object created above as a parameter
NSBatchDeleteRequest *deleteRequest = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fetchRequest];
//Set request result type to count of affected objects
deleteRequest.resultType = NSBatchDeleteResultTypeCount;

//Use the nsbatchdeleteresult object to accept the returned result and obtain the result through the attribute result of ID type
NSError *error = nil;
NSBatchDeleteResult *result = [context executeRequest:deleteRequest error:&error];
NSLog(@"batch delete request result count is %ld", [result.result integerValue]);

//Error handling
if (error) {
    NSLog(@"batch delete request error : %@", error);
}

//Update managed objects in MOC to synchronize MOC and local persistent area data
[context refreshAllObjects];

In most cases, operations involving managed objects need to be loaded into memory. So useCoreDataYou need to pay attention to the use of memory,Do not have too many managed objects in memory。 In the case of system compatibility, when operating with a large amount of data, you shouldTry to use batch processingTo complete the operation.

It should be noted that,refreshAllObjectsFromiOS9It came out atiOS9Before, because of version compatibility, you need to userefreshObject: mergeChanges:Method to update managed objects.

Asynchronous request

//Create the request object and indicate the operation employee table
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

//Create an asynchronous request object and call back through a block. The returned result is an nsaasynchronousfetchresult type parameter
NSAsynchronousFetchRequest *asycFetchRequest = [[NSAsynchronousFetchRequest alloc] initWithFetchRequest:fetchRequest completionBlock:^(NSAsynchronousFetchResult * _Nonnull result) {
    
    [result.finalResult enumerateObjectsUsingBlock:^(Employee * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"fetch request result Employee.count = %ld, Employee.name = %@", result.finalResult.count, obj.name);
    }];
}];

//Execute asynchronous request, and execute the same request method as batch processing
NSError *error = nil;
[context executeRequest:asycFetchRequest error:&error];

//Error handling
if (error) {
    NSLog(@"fetch request result error : %@", error);
}

Pass aboveNSAsynchronousFetchRequestObject creates an asynchronous request and passes theblockMake a callback. IfMultiple requests initiated at the same timeDon’t worry about thread safety, the system will send all asynchronous requestsAdd to an action queue, when the previous task accesses the database,CoreDataThe database will be locked, and subsequent operations will not be performed until the previous execution is completed.

NSAsynchronousFetchRequestProvidedcancelMethod, that is, you can cancel the request during the request. You can also use aNSProgressType to get the request completion progress.NSAsynchronousFetchRequestClass slaveiOS8It can be used at first, so the lower version needs to be version compatible.

Note that when executing the requestMOCConcurrency type cannot beNSConfinementConcurrencyType, this concurrency type has been discarded, which will cause crash.


Many students asked me that I hadDemoNo, in fact, the code posted in the article is a combination ofDemo。 After thinking about it, I still gave this series a simpleDemo, which is convenient for you to run and debug. In the future, all blog articles will be addedDemo

DemoJust to help readers better understand the content of the article,Should blog combineDemoStudy together, just watchDemoStill can’t understand the deeper principleDemoAlmost every line of code in will have a comment. You can break it and followDemoGo through the execution process to see the values of variables in each phase.

Demo address: Liu Xiaozhuang’s GitHub


The article has been updated in the past two daysCoreDataThe six articles in the series are integrated into onePDFVersion of coredata book, on my GitHub.PDFThere is a list of articles on it for easy reading.

If you think it’s good, please transfer PDF to other groups or your friends to let more people know coredata. Thank you!😁

Understanding coredata - using advanced