Tag Archive for XCode

Bad Synchronous Call! Bad!

Back in the dark old days of Commodore 64 and its brethren computers were pretty much all synchronous; instructions executed one after the other, one at a time. It was a simpler time. Users did expect a responsive UI during slow operations or so I have been told. Wondering what a slow operation is? Well, how about any sort of IO? or large data transfer? or how about just pretty much any data transfer over 3G? Of course, there are other cases of long operations but no need to open old wounds….

Now I can hear you already, arguing ‘the platforms today are so much more multi-threaded / multi-core by default I don’t have to worry about writing asynchronous code.’ Well sir (or madam), you are dead wrong. It is true that or more modern platforms have done a lot to run their internal operations in a thread safe / optimized way, but there are a lot of cases where YOU MUST make your code asynchronous. The platform is not going to waive a magic wand and make your operation run asynchronously. Need an example? Here you go:

UIImage* image = [UIImage imageWithData:[NSData dataWithContentsOfURL:someURL]];

Looks reasonable, no? Wrong! That code though deceptively simple is actually very bad. Let’s take a look at what is actually happening in this little one liner:

NSData* imageData = [NSData dataWithContentsOfURL:someURL];
image = [UIImage imageWithData:imageData];

Still pretty simple, right? That’s the exact same functionality as the one linear above and the same problem. Take a closer look at that first line. Pretty simple, right? All it is doing is reading the contents of a URL (in this case an image) downloading the data, and creating an NSData object from it. See the problem yet? That is all happening in order synchronously. If the network is slow or the server is slow to return, the UI on your lovely app will lock for a second or so. Bad UX. Very bad. It is important to note that this code is using one of the most direct ways to create an image from an external service provided wholly by Cocoa. Not to hit this too hard, but the platform vendor’s framework (Cocoa in this case) is not doing anything magical to prevent this from happening. Your code is causing the problem and you have to fix it — yourself.

Oh? You actually want to see a correct version of this code? Well, ok. What needs to happen here is that the image needs to be dealt with asynchronously. I like to use the popular (albeit somewhat dated) iOS / Mac library ASIHTTP to accomplish this. For one request it is really easy:

ASIHTTPRequest* request = [ASIHTTPRequest requestWithURL:someURL];
__weak ASIHTTPRequest* _request = request;
[request setCompletionBlock: ^{
UIImage* image = [UIImage imageWithData:[_request responseData]];
}];
[request setFailedBlock: ^{
// handle failure
}];
[request startAsynchronous];

Not too bad, right? Just a quick walkthrough. If you are new to Cocoa you might not be familiar with the concept of blocks. It’s a pretty big topic and worthy of its own post (or series of posts) but they are similar to closures in other languages. Also, the “__weak” is to prevent a retain cycle for developers using ARC; if you are not using ARC in your new iOS or Mac OS X projects, consider it. Ok so what if you have to deal with a large number of images for something like a UITableView full images? Well check this out:

ASINetworkQueue* q = [[ASINetworkQueue alloc] init];
[q setDelegate:self];
[q setQueueDidFinishSelector:@selector(networkQueueDidFinish:)];
[q setRequestDidFailSelector:@selector(requestDidFail:)];
[q setRequestDidFinishSelector:@selector(requestDidFinish:)];
for (int i = 0; [someArrayOfImagesURLS count]; i++) {
ASIHTTPRequest* imageRequest = [ASIHTTPRequest requestWithURL:[someArrayOfImagesURLS count]];
[q addOperation:imageRequest];
}
[q go];

// delegate methods
- (void) requestDidFail:(ASIHTTPRequest *)request {
// something bad happened -- handle it!
}

- (void) requestDidFinish:(ASIHTTPRequest *)request {
UIImage* image = [UIImage imageWithData:[request responseData]];
// do something with the image
}

- (void) networkQueueDidFinish:(ASINetworkQueue *)q {
// do something magical when the queue is done
}

Ok so all that has changed is that we iterate through an array or URLS for the images, create ASIHTTPRequests based on them, add them to our operation queue, and deal with the delegate methods. One thing of note is that there are separate callbacks for when each individual request finishes and for the queue itself and if you fail to implement one of those required delegate methods your app will crash.

Hope this helps someone. I am going to be posting more about writing asynchronous code to best take advantage of the multi-threaded / multi-core nature of our favorite platforms. Stay tuned for a look at this type of thing on Android! Find me on Google+ or Twitter if you have feedback.


Programming Pitfalls: Bit in the ARC

Apple’s ARC (automatic reference counting) for Mac and iOS devices is intended to make Cocoa development easier. For the most part it does. However, in using it I have encountered a bit of a pitfall: by default the compiler does not optimize your code in debugging but uses its most optimized setting for release.  What does this mean? Well, the more you tell it to optimize your code, the sooner it will release objects for you, which can lead to some issues. To be clear the default settings for each mode are zero optimization and the most possible optimization respectively.

Basically,  a lib I was using was working fine in testing but was throwing BAD_ACCESS errors when running in release mode. After over an hour and half of investigating I found:

The screenshot is showing XCode’s “Build Settings” screen, where you can clearly see that a different level of optimization is being used for the two different modes.

From here the fix is pretty easy: tune down that optimization level. Alternatively, you could dig into the code that is having the issues, but that might turn out to be something of a premature optimization for most needs.

Hope this helps someone. You can find me on Twitter or Google Plus.

All About ARC

ARC (short for automatic reference counting) is one of the most talked about and interesting additions to the iOS developer toolchain. However, in recent conversations with other developers I’ve found that there are a lot of misconceptions surrounding the technology. Hopefully, this clears up some of the confusion.

The first mistake that people often make when talking about ARC is that they equate it to garbage collection in languages such as C# and Java. This is simply incorrect. Boiling it down to its most basic explanation, a garbage collector runs in your application and checks to see what objects are no longer needed and removes them. This means that garbage collectors are very convenient for developers, but they take a small (depending on the implementation) amount of resources themselves. ARC is a special setting that can be set from within XCode that tells the compiler to insert release statements for you. So, this means that when you have ARC enabled the compiler is following the same retain / release rules you would normally follow for your own memory management, but this only happens at compile time, so there is no performance hit and you never see that statements themselves. This is useful because the compiler is far less likely to make a mistake than the average developer, especially in tricky situations, such as those that arise with multiple autorelease pools.

The second common belief developers hold surrounding ARC is that all their projects should use it. For new projects, this makes sense as long as you don’t mind targeting iOS 4.3+. However, converting legacy projects to use ARC can be a little hairy and like all magic that is made for developer convenience, when ARC causes a problem, it tends to be a tough one. Of course, that is not always the case and you mileage will certainly vary, but this is something to consider before hitting that shiny convert button.

Lastly, a number of developers that I have spoken to are under the mistaken impressions that all libs or external projects that you project is taking advantage of must be compatible with ARC for your codebase to use ARC. This is not the case. You can toggle ARC on and off for individual projects within your project (I know that sounds weird to me too) and safely use your legacy C libs or non-ARC Objective-C frameworks.

Overall, ARC is a great addition to the iOS developer’s toolbox, but it is like any other new technology and should be understood for what it is and adopted when appropriate.