Performing block operations on objects in array and completing when all complete

I have an array of objects on which I would like to perform block operations. I am not sure the best way to do this. I am doing something like in the code below but I don’t think this is the best practice.
What is the best way to do such an operation?

- (void)performBlockOnAllObjects:(NSArray*)objects completion:(void(^)(BOOL success))completionHandler {
    NSInteger counter = objects.count;
    for (MyObject *obj in objects) {
        [obj performTaskWithCompletion:^(NSError *error) {
            counter--;
            if (counter == 0) {
                completionHandler(YES);
            }
        }];    
    }
}

  • Creating delegates on the spot with blocks
  • iOS Not the typical background location tracking timer issue
  • Why is Clang confused by @try{} in a block with no return statement?
  • setKeepAliveTimeout and BackgroundTasks
  • didRegisterForRemoteNotificationsWithDeviceToken is not called up in ios 9
  • Should I still copy/Block_copy the blocks under ARC?
  • Solutions Collect From Internet About “Performing block operations on objects in array and completing when all complete”

    Typically you’d use dispatch groups for this. You “enter” the group before you call your method, you “leave” in the completion handler, and then specify a block that should be called when the group notifies you that all “enter” calls have been offset with “leave” calls.

    - (void)performBlockOnAllObjects:(NSArray*)objects completion:(void(^)(BOOL success))completionHandler {
    
        dispatch_group_t group = dispatch_group_create();
    
        for (MyObject *obj in objects) {
            dispatch_group_enter(group);
            [obj performTaskWithCompletion:^(NSError *error) {
                dispatch_group_leave(group);
            }];
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            completionHandler(YES);
        });
    }
    

    This is the typical pattern for specifying a block of code to be called asynchronously when a series of other asynchronous tasks complete.