Promises and ObjectiveC: no more callback hell

If you worked with asynchronous tasks in iOS apps, chances are that you have run into problems when implementing chains of async operations, like when it comes to talking to a server API.

Let’s take an example. Supposing you have to implement a library app and you need to add support for inserting a new book. And supposing the book name validation needs to be done on the server side. And to complicate things even further, the add book API returns only the id of the inserted book. The rest of the details will need to be fetched by making another call to the server. Basically the flow will be as following:

  1. ask the server if the book name is valid
  2. add the book
  3. fetch the book details

How would the ObjectiveC code look like to accomplish this flow? Assuming you’re using AFNetworking directly (although I personally would implement a layer of abstractization over it), one could write it like this:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *bookData = @{@"name": @"Harry Potter"};
[manager POST:@"http://myserver.com/validator/book"
   parameters:bookData
      success:^(AFHTTPRequestOperation *operation, id responseObject) {
          [manager POST:@"http://myserver.com/book"
             parameters:bookData
                success:^(AFHTTPRequestOperation *operation, id responseObject) {
                    [manager GET:[@"http://myserver.com/book/" stringByAppendingString:responseObject]
                      parameters:nil
                         success:^(AFHTTPRequestOperation *operation, id responseObject) {
                             // inform the user that the book was added, move to the appropriate screen
                         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                             if([error.domain isEqual:NSURLErrorDomain]) {
                                 // inform the user that there was a server communication problem
                             } else {
                                 // inform the user that the book could not be added (e.g. it was already added by someone else)
                             }
                         }];
                } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                    if([error.domain isEqual:NSURLErrorDomain]) {
                        // inform the user that there was a server communication problem
                    } else {
                        // inform the user that the book was added, however could not fetch its data
                    }
                }];
      } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
          if([error.domain isEqual:NSURLErrorDomain]) {
              // inform the user that there was a server communication problem
          } else {
              // inform the user that the validation failed (i.e. the book data is not valid)
          }
      }];

Well, the above code has some issues. It has at least three levels of indentation, the failure block has redundant code (although the quantity of redundant code can be decreased), and let’s face it, chaining asynchronous operations this way is tedious and is not very maintainable. And it suffers the unwanted result of moving the code more and more to the right. This problem is very suggestively named “callback hell”.

Another disadvantage of the above is the fact that the final book data, which in our case is a NSDictionary, will need to be casted if we’ll want to access some NSDictionary specific properties. Not having a clear indication in the completion handler about the actual data type makes the code a little ambiguous.

The good news is that there is an alternative to this approach, an alternative that allows you to write code in a sync-ish manner, while not losing the advantages of async execution: promises. Here’s how the add book code would look like if AFHTTPRequestOperation would have a “promise” method that returns a promise:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *bookData = @{@"name": @"Harry Potter"};
[manager POST:@"http://myserver.com/validator/book"
    parameters:bookData].promise.done(^{
    return [manager POST:@"http://myserver.com/book"
              parameters:bookData].promise;

}).success(^(NSString *bookId){
    return [manager GET:[@"http://myserver.com/book/" stringByAppendingString:bookId]
             parameters:nil].promise;

}).success(^(NSDictionary *bookDetails){
    // inform the user that the book was added, move to the appropriate screen

}).failure(^(NSError *error) {
    if([error.domain isEqual:NSURLErrorDomain]) {
        // inform the user that there was a server communication problem
    } else {
        // inform the user about the problem
        // error.domain/error.code can be used to identify which one of the
        // three operations failed
    }
});

The code is cleaner, it’s more readable, it closely follows the synchronous approach, thus the flow is more clear.

If I made you curious, you can read the promise specs here, and if you’re searching for an ObjectiveC implementation, you can find one here.

For now, that’s all about promises. There are much more things to discuss on this, and on the ObjectiveC implementation I mentioned above. I will try to cover those topics in the next articles, meanwhile if you have any questions feel free to add them as comments.

Update: You can check my next article on promises here: http://blog.cristik.com/2015/03/promises-basics/.

How to debug PInvoke-ed C++ DLL from .NET code

If you’ve tried debugging a C++ DLL and could not make Visual Studio to load the debug symbols for that DLL (you kept getting the “The breakpoint will not currently be hit” message), here is something useful I find out on this stackoverflow post: make sure to uncheck the “Enable Just My Code” Visual Studio setting. You need to do this even if the code for that DLL is yours and even in the DLL and the .NET app are in the same solution (my case).

Freelancer messes up with the old vWorker users

So Freelancer finally acquired vWorker. They must be very happy… well, I’m not. Firstly my old password from vWorker no longer worked, then when I tried to recover it it didn’t worked (don’t use the login popup that appears in the left side to reset the password – only the popup from the right side works), and when eventually I was able to reset it, to my own surprize I was not allowed to use my fancy symbols &^$#* – freelancer only accepts alphanumeric characters (what password security is this?).

So if you’re a vWorker account holder and want to see the features that came from freelancer, you’d better make sure you have a password that contains letters and numbers, otherwise you won’t be able to login.

More, you won’t be able to bid on projects until they’re satisfied with the level of profile completion they need for their twisted logics.

My freelancer career ends here… not that I had used it in the past couple of years… I really miss the old rentacoder where you were able to work on projects and be sure that you receive your money if you did your work, no other strings attached, just work. Surely I don’t need a freelancer account where the bureaucracy is similar to the one from Romania.

Setters in Cocoa

Which of the three setters is better:

- (void)setName:(NSString*)value{
    if(value != name){
        [name release];
        name = [value retain];
    }
}

- (void)setName:(NSString*)value{
    id old = name;
    name = [value retain];
    [old release];
}

- (void)setName:(NSString*)value{
    [name autorelease];
    name = [value retain];
}

Personally I’d use the third variant, but I’m open to suggestions 🙂

PHP: mysqli and 64bit numbers – a real pain in the ass

Due to some unfortunate bugs on my project I recently discovered a terrific problem with mysqli and 64bit numbers: no matter you have a 64bit OS and php is compiled for x64, mysqli will truncate the to 32bit any 64bit number when calling the mysqli_stmt::bind_param() method. Due to this  and the fact that I was using memcache to cache the objects, I didn’t noticed that the numbers were not properly saved until a memcached restart.

As replacing mysqli with another mysql driver can be a cumbersome operation on large projects, the simplest appoach to this problem is to have the db type as string and make sure the number goes as string and not as int to the db.

PHP: don’t use time() or microtime() to measure execution time

As Thomas Habets posted on it’s blog (http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time): gettimeofday() and time() should only be used to get the current time if the current wall-clock time is actually what you want. They should never be used to measure time or schedule an event X time into the future.

And because the time() and microtime() function relies on gettimeofday(), those functions don’t provide a reliable way to measure script execution time. The main issue comes from the fact that changing the server date/time directly affects the return value of these functions. As many servers rely on an NTP server to automatically adjust their time, the developers can be easily miss-leaded by some incorrect calculations due to automatically time adjustments.

Godaddy and Google Apps

I recently purchased a godaddy shared web hosting, and although the godaddy configuration tools are way more than I expected for a shared hosting plan (I especially love the ssh access to my account) I’ve run into some issues when I wanted more from their email support.  Basically you have 100MB storage space, but for each email you create you have to allocate an amount of space. Assigning 10MB of storage for an email address is something I find normal, but this limits me to max 10 email addresses. And more, it may happen that one email address rapidly consumes the 10MB allocated, while others stay at almost zero. This means manual reconfiguration of the allocated space for my email addresses. The other big issue is the lack of imap support.

But thanks to this post – http://mike-thomson.com/blog/?p=30 – I find out that the Google emailing capabilities can be combined with my godaddy hosting account. Basically the Google servers will be used for emailing, I get imap support, I benefit of the 7GB of storage, and the most important thing, the email boxes will use the same shared 7GB storage space.

As soon as I’ve completed the steps required by Google Apps, I hit a small issue: sending emails via a 3rd party smtp server is not possible when having a shared hosting plan. This is not a major issue, as you can still use the godaddy relay server (relay-hosting.secureserver.net), but you won’t have those emails in your gmail account. A simple workaround for this is to add a bcc entry with the sender address, this way the email is also delivered into your gmail account.  And if you’d like having that email into the “Sent Mail” folder instead of Inbox, just remove the “Inbox” label from that email (the email is already placed into the sent folder, removing the label keeps things clean).