Category Archives: Advanced Issues

The power of concurrency

Hi everyone, and welcome to Saturday night’s advanced session regarding concurrency in iOS.

We all know that some of Apple’s more powerful devices come equipped with multiple cores and we mostly just trust the operating system to utilize this advantage whenever possible, right? Well, turns out there are some cases where we need to explicitly tell the operating system – ‘hey, this code should be executed concurrently’ (iOS is great, but it’s not a magician). Today, we will discuss one of these cases – concurrent enumeration.

Let’s say we have a huge data collection of independent data points and that we wish to execute some heavy mathematical operation on each of them. Now the mathematical operation(s) we wish to apply on a single object is completely orthogonal to all other objects meaning – this is code that’s ideal for running concurrently between processor cores. The way to do this is to enumerate this data collection with the enumerateObjectsWithOptions:usingBlock: method, like so:

[[arr copy] enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) {
    //Do some heavy mathematical stuff with 'num'
}];

Just to emphasise the performance gain in using this method rather than fast enumeration, check out the output of running a similar scenario on the iOS simulator (yes, that’s why you see 4 cores):

Using simple, fast enumeration:

Simple

Simple enumeration – takes about 5 seconds to run 10000 iterations. You can see that operations run on one core, while the others are simply kicking back with a beer.

 

Using block enumeration with the NSEnumerationConcurrent option:

Concurrent

Now THAT’S team spirit! About 0.5 seconds to run 1000000 iterations. Unbelievable performance gain.

 

That’s it for today! Hope you find creative, safe ways to use this technique and remember – with great power comes great responsibility, so don’t abuse this API by running things in parallel that shouldn’t.

Advanced Issues: Creating custom LLDB object summaries

Update: It’s recommended to read this post before diving in.

Today we’re going to talk about an advanced XCode debugging feature that might improve your bug-extermination practices and efficiency. It’s well known that XCode has great debugging features, some of which were even discussed here in a previous post. These features are sometimes very straightforward and easy to use, but some of them require a bit of digging.

This is the digging kind.

What I’m going to show you is how to create a python script that will “teach” XCode and the LLDB about your object structures – this way, you will be able to immediately get a custom summary of the object you’re reviewing in the debugger and see what’s important to you while debugging.

For the sake of this tutorial, We’ll use a wonderful and widely-popular class called “Beer”. Let’s say that a “Beer” has a name, a price and a rating:

Screen Shot 2013-01-06 at 8.28.13 PM

The problem is that when we use the XCode debugger to inspect a beer object instance, we will automatically be able to see only the pointer address of the instance. This is unlike an NSArray object or an NSString object for instance – in these cases we’ll see the amount of objects in the array or the string itself, respectively. So who the hell cares about the beer’s pointer?? Let’s make this right.

The debugger watchlist - notice the unfair treatment NSArray is getting over Beer. That's just wrong.

The debugger watchlist – notice the unfair treatment NSArray is getting over Beer. Not cool.

So, let’s get started with the Python script that will eventually enable us to see a better summary:

Step 1: Create the Python script.

Create a new “CustomSummaries.py” file and base it on the following code:

Screen Shot 2013-01-06 at 9.13.37 PM

I added this as a screenshot on purpose so that you’ll have to do some work. Lazy bastards.

Here’s what you need to know:

Line 1 – imports the lldb library. Must be in your script in order to work.

Lines 7-8 – This function gets called by default and attaches your custom object summary function to the “Beer” object. Make sure you don’t misspell anything here and that you include all the flags as written above. Replace any “Beer” instance with your own class name.

Line 3-5: This is the definition of the object summary – we extract only the beer’s name and return a string that includes a “name: ” prefix followed by the beer name itself. Note that on line 4 we extract the _name property as defined in the “Beer” class.

The result:

Screen Shot 2013-01-06 at 9.18.41 PM

You can now see the beer name, inline like it were a string object. There’s no need to open the object hierarchy to inspect the beer, it’s right there in front of you.

Step 2: Automate the import

In order for XCode to recognise and run your new script, you’ll have to create a new file in your home folder called “.lldbinit” so that the full path to this file is: ~/.lldbinit

Within this file, add the following line:

command script import PATH_TO_PY_FILE

Make sure you supply the correct, full path to CustomSummaries.py and that’s it, XCode will now include this custom summary every time you run it. If XCode is already running, be sure to restart it in order to see the changes taking place. Enjoy!

Screen Shot 2013-01-06 at 8.31.08 PM

This is how geeks import beer. Geeks, not me.

Advanced issues: Asynchronous UITableViewCell content loading done right

Problem?

Haven’t you always wondered why your UITableView is loading “almost” perfectly? I mean, sure- you’ve made it clear to the iOS that all non-trivial cell work (such as downloading images from a remote URL or rendering content) is to be computed asynchronously on a background thread. But sometimes this is not enough, mainly for 2 reasons:

1. Once a cell is out of the visible area, the asynchronous operation you called is still doing work. This often results in unnecessary system resource usage or even buggy table behaviour caused by operations not knowing which cell to return to when they’re done.

2 . UITableViewCells are often reused instances. This means that cells being loaded into the view may sometimes contain data that was loaded originally into a completely different cell. This often causes a “Cell switching” behaviour which can just completely piss you off.

Solved!

First of all it’s important to understand that there are many ways to tackle this issue – some are great ideas and some are, well, awful. The method that I’m about to describe here is based on a demo provided by Apple (namely WWDC 2012 session 211), and you know those guys know a thing or two about iOS.

For our example, I’ll use a simple UITableView instance that is meant for displaying your facebook friends’ names and profile pictures. The main idea is that we start loading the profile images when UITableViewDataSource’s tableView:cellForRowAtIndexPath: is called. If the operation succeeds and the cell is still in view then we simply add the image to the cell’s profile image view (on the main thread). If it’s not – we make sure not to perform the “setImage” part.

Before you start, some prep work: Define an NSOperationQueue for running background operations – in this example, we call it the imageLoadingOperationQueue. Also, define an NSMutableDictionary for storing references to specific operations – in this example we will map the facebook unique ids to the operations on the facebookUidToImageDownloadOperations dictionary.

Most of the important stuff is commented in the code so make sure you read the comments to understand what’s going on:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    FacebookFriend *friend = [self.facebookFriends objectAtIndex:indexPath.row];
    FacebookFriendCell *cell = [tableView dequeueReusableCellWithIdentifier:FB_CELL_IDENTIFIER forIndexPath:indexPath];
    cell.lblName.text = friend.name;

    //Create a block operation for loading the image into the profile image view
    NSBlockOperation *loadImageIntoCellOp = [[NSBlockOperation alloc] init];
    //Define weak operation so that operation can be referenced from within the block without creating a retain cycle
    __weak NSBlockOperation *weakOp = loadImageIntoCellOp;
    [loadImageIntoCellOp addExecutionBlock:^(void){
        //Some asynchronous work. Once the image is ready, it will load into view on the main queue
        UIImage *profileImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:friend.imageUrl]]];
        [[NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
            //Check for cancelation before proceeding. We use cellForRowAtIndexPath to make sure we get nil for a non-visible cell
            if (!weakOp.isCancelled) {
                FacebookFriendCell *theCell = (FacebookFriendCell *)[tableView cellForRowAtIndexPath:indexPath];
                [theCell.ivProfile setImage:profileImage];
                [self.facebookUidToImageDownloadOperations removeObjectForKey:friend.uid];
            }
        }];
    }];

    //Save a reference to the operation in an NSMutableDictionary so that it can be cancelled later on
    if (friend.uid) {
        [self.facebookUidToImageDownloadOperations setObject:loadImageIntoCellOp forKey:friend.uid];
    }

    //Add the operation to the designated background queue
    if (loadImageIntoCellOp) {
        [self.imageLoadingOperationQueue addOperation:loadImageIntoCellOp];
    }

    //Make sure cell doesn't contain any traces of data from reuse -
    //This would be a good place to assign a placeholder image
    cell.ivProfile.image = nil;

    return cell;
}

Now all that’s left to do is to take advantage of a new UITableViewDelegate method introduced in iOS 6.0: It’s called “tableView:didEndDisplayingCell:forRowAtIndexPath:” and It’s called right after the cell we are loading our data into is no longer needed. Sounds like a perfect spot for the following code, which fetches the relevant operation and cancels it:

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    FacebookFriend *friend = [self.facebookFriends objectAtIndex:indexPath.row];
    //Fetch operation that doesn't need executing anymore
    NSBlockOperation *ongoingDownloadOperation = [self.facebookUidToImageDownloadOperations objectForKey:friend.uid];
    if (ongoingDownloadOperation) {
        //Cancel operation and remove from dictionary
        [ongoingDownloadOperation cancel];
        [self.facebookUidToImageDownloadOperations removeObjectForKey:friend.uid];
    }
}

Also, don’t forget to take advantage of the NSOperationQueue and call “cancelAllOperations” when the table is not needed anymore:

- (void)viewDidDisappear:(BOOL)animated {
    [self.imageLoadingOperationQueue cancelAllOperations];
}

That’s it! You now have yourself a UITableView running as smooth as a Ferrari. You’re welcome 😉

Table_Mountain_DanieVDM

Tabelview, Capetown