Blog

Block-based callbacks in Backendless SDK for iOS

by on July 26, 2013

Blocks are a powerful C-language feature that is part of Cocoa application development. They are similar to “closures” and “lambdas” you may find in scripting and programming languages such as Ruby, Python, and Lisp. For a more in-depth review of blocks, see “a short practical guide to blocks”. A Backendless user has recently asked us about the ability to handle asynchronous APIs via block-based callbacks. Since this is a very reasonable request, we added support for blocks and it is available in the latest version of the Backendless SDK for iOS. Below is an example of using the new feature with the user registration and login APIs (btw, the feature is available for ALL Backendless APIs):

-(viod)registerUserAsync {
    NSString *userName =@"user2";
    NSString *password = @"87654321";
    BackendlessUser *user = [BackendlessUser new];
    user.email = [NSString stringWithFormat:@"%@@foo.com", userName];
    user.password = password;
    user.name = userName;
    [backendless.userService
     registering:user
     response:^(BackendlessUser *registeredUser) {
        [self onRegister:registeredUser];
         [backendless.userService
          login:registeredUser.email password:password
          response:^(BackendlessUser *response) {
              [self onLogin:backendless.userService.currentUser];
              [backendless.userService
               logout:^(id response) {
                   [self onLogout:backendless.userService.currentUser];
               }
               error:^(Fault *fault){
                   [self onError:fault];
               }
               ];
          }
          error:^(Fault *fault){
              [self onError:fault];
          }
          ];
     }
     error:^(Fault *fault){
         [self onError:fault];
     }
     ];
}

By the way, here is an example of code that does the same thing, but synchronously:

-(viod)registerUserSync {
    @try {
        NSString *userName = @"user1";
        NSString *password = @"12345678"
        BackendlessUser *user = [BackendlessUser new];
        user.email = [NSString stringWithFormat:@"%@@foo.com", userName];
        user.password = password;
        user.name = userName;
        BackendlessUser *registeredUser = [backendless.userService registering:user];
        [self onRegister:registeredUser];
        [backendless.userService login:registeredUser.email password:password];
        [self onLogin:backendless.userService.currentUser];
        [backendless.userService logout];
        [self onLogout:backendless.userService.currentUser];
    }
    @catch (Fault *fault) {
        [self onError:fault];
    }
}

The example below demonstrates the usage of block callbacks with the Data Service API in order to:

  • Persist a complex type (an instance of class Weather)
  • Find an object by ID
  • Finding first and last instances
  • Deleting an object by its objectId
-(void)entitySaveAsync {
    __block Weather *entity = [Weather new];
    [backendless.persistenceService
     save:entity
     response:^(id response) {
         entity = (Weather *)response;
         [self onResponse:entity action:@"BLOCKS!!! entitySave (save)"];
         [backendless.persistenceService
          findByClassId:[entity class] sid:entity.objectId
          response:^(id response) {
              entity = (Weather *)response;
              [self onResponse:entity action:@"BLOCKS!!! entitySave (findByClassId)"];
              [backendless.persistenceService
               first:[entity class]
               response:^(id response) {
                   entity = (Weather *)response;
                   [self onResponse:entity action:@"BLOCKS!!! entitySave (first)"];
                   [backendless.persistenceService
                    last:[entity class]
                    response:^(id response) {
                        entity = (Weather *)response;
                        [self onResponse:entity action:@"BLOCKS!!! entitySave (last)"];
                        [backendless.persistenceService
                        remove:[entity class] sid:entity.objectId
                         response:^(NSNumber *response) {
                             [self onResponse:response action:@"BLOCKS!!! entitySave (remove)"];
                         }
                         error:^(Fault *fault){
                             [self onError:fault];
                         }
                         ];
                    }
                    error:^(Fault *fault){
                        [self onError:fault];
                    }
                    ];
               }
               error:^(Fault *fault){
                   [self onError:fault];
               }
               ];
          }
          error:^(Fault *fault){
              [self onError:fault];
          }
          ];
     }
     error:^(Fault *fault){
         [self onError:fault];
     }
     ];
}

If you prefer to use the synchronous (blocking) API, the follow code does the same thing as the example above (but synchronously):

-(void)entitySaveSync {
    Weather *entity = [Weather new];
    @try {
        entity = [backendless.persistenceService save:entity];
        [self onResponse:entity action:@"SYNC!!! entitySave (save)"];
        entity = [backendless.persistenceService findByClassId:[entity class] sid:entity.objectId];
        [self onResponse:entity action:@"SYNC!!! entitySave (findByClassId)"];
        entity = [backendless.persistenceService first:[entity class]];
        [self onResponse:entity action:@"SYNC!!! entitySave (first)"];
        entity = [backendless.persistenceService last:[entity class]];
        [self onResponse:entity action:@"SYNC!!! entitySave (last)"];
        NSNumber *result = [backendless.persistenceService remove:[entity class] sid:entity.objectId];
        [self onResponse:result action:@"SYNC!!! entitySave (remove)"];
    }
    @catch (Fault *fault) {
        [self onError:fault];
    }
}

Enjoy!

Leave a Reply