3

There are quite many questions about this kind of question, but I can't find any for CoreData. The problem is: I want to update a large amount of NSManagedObject (you can think of resetting a property's of a large amount of NSManagedObject).

Right now, all I can think of is:

  1. Fetch all object.
  2. Loop through all of it, using forin-loop.
  3. Setting the property in each for block.

The data might be large, and I also want to write a Utility for this action. So the question is:

Is there any more efficient way to perform this? I don't believe using for-loop is efficent.

BONUS QUESTION

Also, I would like to delete all object that satisfied a condition (most likely a boolean flag). My solution is rather simple like the one above:

  1. Fetch all object, with NSPredicate and condition.
  2. Loop through all, forin.
  3. Delete each one of it.

Same question for solution.

The real problem

The real problem is, I want to set all the object's flag (call it willDelete) = YES. Then synchronize from server, then update them and set willDelete = NO. After that, whichever has willDelete = YES would be delete from context.

EDIT 1

My question might be different this one. I want to update the property first. And I care about performance time, not the memory.

EDIT 2

Okay, I managed to use NSBatchUpdateRequest. But the problem is: I got nsmergeConflict. Not sure what to do with this progress. Here's the code anyway:

- (void)resetProductUpdatedStatus
{
        NSBatchUpdateRequest *request = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:NSStringFromClass([Product class])];
        request.propertiesToUpdate = @{@"hasUpdated" : @(NO)};
        request.resultType = NSUpdatedObjectIDsResultType;
        NSBatchUpdateResult *result = (NSBatchUpdateResult *)[[CoreDataUtil managedObjectContext] executeRequest:request error:nil];
        [result.result enumerateObjectsUsingBlock:^(NSManagedObjectID *objId, NSUInteger idx, BOOL *stop) {
            NSManagedObject *obj = [[CoreDataUtil managedObjectContext] objectWithID:objId];
            if (!obj.isFault) {
                [[CoreDataUtil managedObjectContext] refreshObject:obj mergeChanges:YES];
            }
        }];
}

This will set all hasUpdated = NO. Next, I'll perform the sync progress. With all the products caught from the synchronization will update the hasUpdated = YES. Next perform delete:

- (void)updateProductActiveStatus
{
        NSBatchUpdateRequest *request = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:NSStringFromClass([Product class])];
        request.predicate = [NSPredicate predicateWithFormat:@"hasUpdated = NO"];
        request.propertiesToUpdate = @{@"isActive" : @(NO)};
        request.resultType = NSUpdatedObjectIDsResultType;
        [[CoreDataUtil managedObjectContext] executeRequest:request error:nil];
}

As you can see, I've deleted the merge in the update status. So probably, it cause merge conflict in the reset status. So, I guess I will have to fix the merge progress. So I'll ask to people here if you have any idea about this.

Community
  • 1
  • 1
Eddie
  • 1,903
  • 2
  • 21
  • 46
  • Possible dublicate of [How to delete large chunks of core data objects](http://stackoverflow.com/questions/10581569/what-is-the-most-efficient-way-to-delete-a-large-number-10-000-objects-in-cor) – Saheb Roy Sep 04 '15 at 12:46
  • 1
    If your's deployment target at least IOS 8, you can use `NSBatchUpdateRequest` else you need do this with each object one by one. – Cy-4AH Sep 04 '15 at 12:50
  • @Cy-4AH my app target is at least 7. So your answer is there is no solution other than the for-loop? – Eddie Sep 04 '15 at 12:55
  • @Cy-4AH man, NSBatchUpdateRequest's availability is iOS 5.0 and later. That might work. Let me test it for a while. – Eddie Sep 04 '15 at 13:04
  • see my answer here https://stackoverflow.com/a/66635329/1703291 – MMujtabaRoohani Mar 15 '21 at 09:26

1 Answers1

1

Here you can also check the time taken for badge update is quite less than what happens in normal update .As in batchupdate we don't need to fetch the data from file itself. Also check my github link : https://github.com/tapashm42/CoreDataInSwift.git . I am working on the batchdelete part as well.

func batchUpdate(entityName: String,context:NSManagedObjectContext)  {
        let batchUpdateRequest = NSBatchUpdateRequest(entityName: entityName)
        batchUpdateRequest.propertiesToUpdate = ["name":"Tapash Mollick","designation":"Associate IT Consultant"]
        batchUpdateRequest.resultType = .updatedObjectIDsResultType
        do {
            let start = Date().currentTimeMillis
            let batchUpdateResult = try context.execute(batchUpdateRequest) as! NSBatchUpdateResult
            let result = batchUpdateResult.result as! [NSManagedObjectID]
            print("time taken to update\(Date().currentTimeMillis - start)")
            for objectId in result {
                let manageObject = context.object(with: objectId)
                if (!manageObject.isFault) {
                context.stalenessInterval = 0
                context.refresh(manageObject, mergeChanges: true)
                }
            }
        }
        catch{
            fatalError("Unable to batchUpdate")
        }
    }

extension Date{
    var currentTimeMillis: Int64 {
        return Int64(Date().timeIntervalSince1970 * 1000)
    }
}
Tapash Mollick
  • 135
  • 1
  • 11