You have found PodioKit, the official Objective-C SDK for Podio. It works with both iOS and Mac OS X.

Build Status

For help post on Stack Overflow and tag with podio. For bugs create an issue on GitHub.

Basic Principles of Asynchronicity

PodioKit’s main responsibility os making request to the Podio API. To do so, it needs to provide a mean of handling asynchronous method calls. PodioKit uses a future-based approach where each asynchronous method returns an instance of PKTAsyncTask. You can then register callbacks (onSuccess:, onError: and onComplete:) on this tasks that will be called according to the following rules:

To register a callback, you have three options:

The onSuccess: method is used to register callbacks to be executed if the task succeeds, meaning it does not generate an error:

PKTAsyncTask *task = [SomeClass someAsynchronousMethod];

[task onSuccess:^(PKTResponse *response) {
  // The task finished successfully
}];

The onError: method can be used to register callbacks for the error case:

PKTAsyncTask *task = [SomeClass someAsynchronousMethod];

[task onError:^(NSError *error) {
  // The task failed and returned an error
}];

If you are interested in both the success and error case at the same time, you can use the onComplete: method to register a callback for when either happens:

PKTAsyncTask *task = [SomeClass someAsynchronousMethod];

[task onComplete:^(PKTResponse *response, NSError *error) {
  if (!error) {
    // Task succeeded
  } else {
    // Task failed
  }
}];

The main advantage of modelling asynchronisity with futures is that you can chain tasks together to acheive some things. PodioKit provides a few combinator methods to combine sub-tasks in to bigger tasks. Consider for example if you first want to upload a task, then attach it to an object. With a callback approach you would have to nest your callback handlers:

NSData *data = ...; // Some image data

[PKTFile uploadWithData:data fileName:@"image.jpg" completion:(PKTFile *file, NSError *error) {
  if (!error) {
    [file attachWithReferenceID:1234 referenceType:PKTReferenceTypeItem completion:^(PKTResponse *response, NSError *error) {
      if (!error) {
        // Handle success...
      } else {
        // Handle failure...
      }
    }];
  } else {
    // Handle failure...
  }
}];

You can see that we have to handle the error case twice. With a task based approach, we can instead use the pipe: combinator method which takes a block that generates a new task based on the result of the first task once completed:

NSData *data = ...; // Some image data

PKTAsyncTask *uploadTask = [PKTFile uploadWithData:data fileName:@"image.jpg"];

PKTASyncTask *task = [uploadTask pipe:^PKTAsyncTask *(PKTFile *file) {
  return [file attachWithReferenceID:1234 referenceType:PKTReferenceTypeItem];
}];

[task onComplete:^(PKTResponse *response, NSError *error) {
  if (!error) {
    // Handle success...
  } else {
    // Handle failure...
  }
}];

Here, we only have to handle the error case once and we do not end up with deeply nested code blocks. There are also other useful combinator methods such as when:, then: and map: available.