Grand Central Dispatch, or GCD for short, is a C API that makes it exceptionally easy to perform asynchronous operations in iOS. Asynchronous operations are a fundamental part of every iOS app when you want to perform long operations without freezing or blocking the user interface. You can image that if your entire app froze without warning then your users would get quite irritated.
With GCD, you can line up blocks of code in a queue for the system to execute as necessary. These blocks or operations, will be dispatched in the queue to another thread, leaving your main UI thread to continue its tasks. It’s important to know that GCD will use separate threads for it’s operations but which thread it isn’t important to you. All that matters is that your long running process in a separate thread outside the main thread where your UI and gestures are running.
GCD queues can be concurrent or serial but serial queues (where there is one queue and each item is executed one after the other in order) are easier to understand so we’ll look at those.
The more important functions you’ll need are for creating the queue:
dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
and adding blocks to the queue:
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
There’s also a couple helper functions for retrieving specific queues such as:
dispatch_queue_t dispatch_get_current_queue(void);
dispatch_queue_t dispatch_get_main_queue(void);
The dispatch_get_current_queue function will return the current queue from which the block is dispatched and the dispatch_get_main_queue function will return the main queue where your UI is running.
The dispatch_get_main_queue function is very useful for updating the iOS app’s UI as UIKit methods are not thread safe (with a few exceptions) so any calls you make to update UI elements must always be done from the main queue.
A typical GCD call would look something like this:
// Doing something on the main thread
dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);
dispatch_async(myQueue, ^{
// Perform long running process
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
});
});
// Continue doing other stuff on the
// main thread while process is running.
GCD relies on block so it has a really nice, readable syntax. It becomes clear what happes in the background thread and the main thread. For example, here’s how you might load a few images:
NSArray *images = @[@"http://example.com/image1.png",
@"http://example.com/image2.png",
@"http://example.com/image3.png",
@"http://example.com/image4.png"];
dispatch_queue_t imageQueue = dispatch_queue_create("Image Queue",NULL);
for (NSString *urlString in images) {
dispatch_async(imageQueue, ^{
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
NSUInteger imageIndex = [images indexOfObject:urlString];
UIImageView *imageVIew = (UIImageView *)[self.view viewWithTag:imageIndex];
if (!imageView) return;
dispatch_async(dispatch_get_main_queue(), ^{
// Update the UI
[imageVIew setImage:image];
});
});
}
// Continue doing other stuff while images load.
You’ll notice I check for imageView before dispatching to the main thread. This avoids the main queue dispatch if the network request took a long time and the imageView is no longer there for one reason or another. Once a block has been dispatched onto a queue, it’s not possible to stop it. The block will execute to completion and there’s nothing you can do. If you have a very long running process, such as loading a URL, you should add logic between each step to check to see if it should continue and if it’s still appropriate to finish the operation.
That’s it. Start build queues and making your UI more responsive.
Aside: Concurrency
If you want to run a single independent queued operation and you’re not concerned with other concurrent operations, you can use the global concurrent queue:
dispatch_queue_t globalConcurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
This will return a concurrent queue with the given priority as outlined in the documentation:
DISPATCH_QUEUE_PRIORITY_HIGH Items dispatched to the queue will run at high priority, i.e. the queue will be scheduled for execution before any default priority or low priority queue.
DISPATCH_QUEUE_PRIORITY_DEFAULT Items dispatched to the queue will run at the default priority, i.e. the queue will be scheduled for execution after all high priority queues have been scheduled, but before any low priority queues have been scheduled.
DISPATCH_QUEUE_PRIORITY_LOW Items dispatched to the queue will run at low priority, i.e. the queue will be scheduled for execution after all default priority and high priority queues have been scheduled.
DISPATCH_QUEUE_PRIORITY_BACKGROUND Items dispatched to the queue will run at background priority, i.e. the queue will be scheduled for execution after all higher priority queues have been scheduled and the system will run items on this queue on a thread with background status as per setpriority(2) (i.e. disk I/O is throttled and the thread’s scheduling priority is set to lowest value).
from queue.h
I’ve been setting up Jenkins CI at work for all our mobile platforms (which is awesome) but one problem I encountered with our android deployments was that the default APK file names were simply ProjectName-release.apk. I wanted to have the build process add the version number to the APK file but locating the file after the build and renaming it was a lame solution. Instead, I wanted the Android build process to use the right file name from the start so I thought I’d share how I did it.
First I set up the project to use Ant as outlined in the Building and Running from the Command Line Google docs. This allows you to use ant release to build your project without eclipse (Jenkins has ant integration as well). The most recent version of the Android SDK also allows you to include a custom_rules.xml for your custom Ant build rules. These are imported by the build.xml file and executed in the Ant build process. Here’s the custom rules I created to add the version number from the AndroidManifest.xml to the apk file name:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<target name="rename-release-with-version-number">
<xmlproperty file="AndroidManifest.xml"
prefix="themanifest"
collapseAttributes="true"/>
<!-- see ${sdk.dir}/tools/ant/build.xml -set-release-mode -->
<property name="out.packaged.file"
location="${out.absolute.dir}/${ant.project.name}-${themanifest.manifest.android:versionName}-release-unsigned.apk" />
<property name="out.final.file"
location="${out.absolute.dir}/${ant.project.name}-${themanifest.manifest.android:versionName}-release.apk" />
</target>
<target name="-set-release-mode"
depends="rename-release-with-version-number,android_rules.-set-release-mode">
<echo message="target: ${build.target}"></echo>
</target>
</project>
The -set-release-mode target overrides the same target in ${sdk.dir}/tools/ant/build.xml where the out.final.file file name is originally defined. To add the version number, I override -set-release-mode by calling my rename-release-with-version-number target in the dependencies and then calling the original android_rules.-set-release-mode to finish any other setup there.
The rename-release-with-version-number target simply reads in the manifest and adds the version number to both out.final.file and out.packaged.file.
Now the build APK is ProjectName-version-release.apk and it’s automatically used by the rest of the ant build process without clumsy file renaming.
No matter how experience you are in your platform of choice, you should never stop actively learning. I make it a habit to keep track of the latest changes in iOS and Objective C and take advantage of them wherever I can. Here’s a list of a few resources I’ve found that are very helpful.
On-Line Courses
There’s a number of great – and free – online courses you can work though in iTunes U. These few are from Stanford and the last one is currently in progress, covering iOS6, storyboards and all the new stuff int he latest iOS SDK’s.
Objective-C / iOS Topic Blogs
You can fill your RSS reader with lots of blogs but these are a few low-frequency but high quality ones I’ve come across. NSHipster is especially nice in that it provides a weekly in-depth look at parts of Objective-C that are often overlooked.
As well, here’s a few personal blogs by other developers that sometimes wander off topic but are still full of great content.
Pod Casts
Plug in for the commute or an evening’s rest. Some of these shows are lengthy and can’t be consumed in one quick sitting but there’s lots of interesting ideas and interviews.
Screen Casts
Reading is great but sometimes is easier to actually see something in action. Check out these great resources direct from Apple, along with a couple others.
Books
Books are still awesome. Soe would argue that blogs rule, but it’s extra nice to have a well organized book with in-depth coverage of the topic you’re working on. Here’s a few I’ve read and recommend.
Documentation, Project Resources & Sample Code
Last but not least, don’t forget about documentation and sample code you can find scattered over the web. Learning from other developer’s code is often a great way to pick up new techniques.
So, I’ve been watching the new Standford Coding Together series by Paul Hegarty and apparently I’ve been living under a rock because I completely missed the introduction of IBOutletCollections in iOS 4 (mentioned in Lesson 3). These collections allow you to assign multiple objects to a single outlet, giving you an array of the objects in the storyboard.
For example,
@property (nonatomic, retain) IBOutletCollection(UISwitch) NSArray *switchCollection;
would allow you to connect multiple switches to the single switchCollection outlet. Then you could use simple key/value coding to quickly toggle all the values:
[switchCollection setValue:@(NO) forKey:@"on"];
I’ve had a few projects where this would have come in handy and saved creating multiple outlets.
Apple recently updated Technical Q&A QA1633 related to creating short links to the App Store for your apps and company profiles.
Now you can use the AppStore.com domain to create links to both your company and apps.
So, instead of this:
https://itunes.apple.com/ca/artist/tropical-pixels/id307208658
you can do this:
AppStore.com/tropicalpixels
Or for iOS apps:
AppStore.com/wordswithin
For the Mac App store, the same format applies except you need to add /mac/ into the url, for example:
AppStore.com/mac/tropicalpixels
To figure out your url for your app, Apple indicates you need to apply the following rules to your app (or company) name:
- Remove all whitespace
- Convert all characters to lower-case
- Remove all copyright (©), trademark (™) and registered mark (®) symbols
- Replace ampersands (”&”) with “and”
- Remove most punctuation including
!¡"#$%'()*+,\-./:;<=>¿?@[\]^_`{|}~
- Replace accented and other “decorated” characters (ü, å, etc.) with their elemental character (u, a, etc.)
- Leave all other characters as-is.
Personally, I like this AppStore.com url because it never seemed right to me when I was linking to “iTunes” for an app.
I’ve migrated this blog (again, I know) and have finally settled on Jekyll and Markdown as my publishing platform. The only thing I didn’t like about it was the lack of a quick publishing workflow for my drafts, so I wrote a small plugin to handle the process.
First off, I added a _drafts and a _publish folder to the root of my Jekyll install:
.
|-- _config.yml
|-- _drafts
| `-- jekyll-draft-publishing-plugin.md
|-- _includes
|-- _layouts
| |-- default.html
| `-- post.html
|-- _posts
| |-- 2013-01-28-mklocalsearch-example.md
| `-- 2013-1-31-generate-xcode-warnings-from-todo-comments.md
|-- _publish
|-- _site
`-- index.html
Next, I added the following publisher.rb plugin to the _plugins folder:
module Jekyll
class PostPublisher < Generator
safe false
def replace(filepath, regexp, *args, &block)
content = File.read(filepath).gsub(regexp, *args, &block)
File.open(filepath, 'wb') { |file| file.write(content) }
end
def generate(site)
@files = Dir["_publish/*"]
@files.each_with_index { |f,i|
now = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
replace(f, /^date: unpublished/mi) { |match| "date: \"" + now + "\"" }
now = Date.today.strftime("%Y-%m-%d")
File.rename(f, "_posts/#{now}-#{File.basename(f)}")
}
end
end
end
Gist Source: https://gist.github.com/4689219
With this in place, I can leave the date off my draft file name, for example:
_drafts/jekyll-draft-publishing-plugin.md
and when I finish writing the post, I just move it to the _publish folder.
_publish/jekyll-draft-publishing-plugin.md
The Jekyll plugin takes care of adding the Y-m-d to the beginning of the file and moves in into the _posts folder.
_posts/2013-02-01-jekyll-draft-publishing-plugin.md
Also, for more accurate date sorting my default YAML template includes a date: unpublished tag:
---
title: ""
date: unpublished
layout: post
tags:
---
Post content
The publisher.rb plugin automatically replaces date: unpublished with a timestamp when the post is published:
---
title: ""
date: "2013-02-01 09:29:16"
layout: post
tags:
---
Post content
This simplifies a few steps in the workflow, removing the manual date entry and I can use dropbox and iOS apps to manage the _drafts and _publish folders while Jekyll can run on a different machine to update the site.
Next I’ll update the plugin to allow scheduling posts for the future.
Well written code doesn’t have compiler warnings or errors. I like to keep my code warning free so that I know that when one does appear, it means something important. Xcode already warns about a number of common problems but ones that are often overlooked are TODO and FIXME comments.
To help me keep my code running smooth, I like to have warnings in the build log if there are any TODO’s left in the code. This helps remind me about unfinished tasks or lets me know when another developer may not have finished something.
Originally I was using the compiler warnings for todo’s such as this:
#warning TODO: Finish this code
but that will only warn on the TODO’s that have been properly prefixed with #warning, something that only I was doing, not my fellow developers. Instead, what I wanted to do was warn if there were any comments similar to:
// TODO: Finish this code
After a bit of experimentation I realized this is quite easy to do using the Build Phases in an Xcode target.
To set this up in your projects, select your target and then select the Build Phases tab. At the bottom of the window you’ll see an option to Add Build Phase at the bottom of the screen. You can use the Add Build Phase to add a Run Script build phase. The Run Script option allows you to select a shell and execute arbitrary code against the project.
To warn about TODO comments, use /bin/sh as the shell and paste in this script:
TAGS="TODO:|FIXME:"
echo "searching ${SRCROOT} for ${TAGS}"
find "${SRCROOT}" \( -name "*.h" -or -name "*.m" \) -print0 | xargs -0 egrep --with-filename --line-number --only-matching "($TAGS).*\$" | perl -p -e "s/($TAGS)/ warning: \$1/"
Now, when the target builds it will run the bash script to locate any .h or .m files that contain TODO: or FIXME: and create a warning in the Xcode build log.
In some projects you’ll be surprised about how many buried TODOs may have been forgotten.
Apple released iOS 6.1 today and one of the new developer features is access to the built in MKMapKit search api, better know as MKLocalSearch (docs). Accessing the search api allows you to use Apple Maps’s natural language searching to look for and display locations within your own app (though we all know how the initial Map launch went so depending on your area the quality of the results may vary).
To demonstrate the functionality, I’ve created a quick Git repo that shows MKLocalSearch in action. Feel free to download it an play.
The basic usage requires you to set up an MKLocalSearchRequest that contains a search region and the natural language query:
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = searchBar.text;
request.region = self.ibMapView.region;
For demonstration purposes, my region is defined by the visible MKMapView (from the Interface Builder storyboard) and the natural language query is whatever you type into the search bar. This way you can experiment with search terms.
The MKLocalSearchRequest is then used to create an instance of MKLocalSearch. The search uses a block completion handler to return an MKLocalSearchResponse object with and array of MKItems:
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (error != nil) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Map Error",nil)
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
return;
}
if ([response.mapItems count] == 0) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Results",nil)
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
return;
}
results = response;
[self.searchDisplayController.searchResultsTableView reloadData];
}];
In the demo I’m simply storing the response and using it to display the MKItems in the search display controller’s results table.
The guts of the example is in ViewController.m so start there.
If you haven’t yet, go watch the Debugging talk from CocoaHeads by Mike Hay for some great Xcode debugging tips. If you didn’t know about things like the exception breakpoint you’ll be much happier.
One item Mike discussed was using UIView’s recursiveDescription method in the LLDB debugger to see the view hierarchy of the current screen. This is a great way to debug your view layouts but typing po [[[UIApplication sharedApplication] keyWindow] recursiveDescription] into the debugger is tiresome.
Instead, try this quick tip:
Create an .lldbinit file in your home directory (~/.lldbinit) and add the following:
command regex rd 's/^[[:space:]]*$/po [[[UIApplication sharedApplication] keyWindow] recursiveDescription]/' 's/^(.+)$/po [%1 recursiveDescription]/'
Now debugging the recursive description is a easy as pausing and entering rd in the debugger.
(lldb) rd
$0 = 0x0a498210 <UIWindow: 0xa57e5b0; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0xa57b720>>
| <UILayoutContainerView: 0xc0b3360; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0xc0b3420>>
| | <UILayoutContainerView: 0xc0b4010; frame = (321 0; 703 748); clipsToBounds = YES; layer = <CALayer: 0xc0b4080>>
…etc…
For more fine grained control set a breakpoint in a view controller controller and use rd self.view:
(lldb) rd self.view
Now go fix those layouts!
While cleaning up warnings and errors in Xcode projects I often come across this error related to Storyboards:
warning: Unsupported Configuration: Minimum Font Size greater than current font size.
Locating the error is a problem because clicking on it in the error list just opens the storyboard and doesn’t tell you which field has the problem. The easiest way I’ve found to locate the error is to open the storyboard as Source Code and search for minimumFontSize. For each result check the associated fontDescription node and ensure that the pointSize is equal to or greater than the minimumFontSize. For example, here’s what was producing the error (truncated for the example):
<label … minimumFontSize="10" id="rMR-J8-TZc">
<fontDescription key="fontDescription" type="system" pointSize="9"/>
</label>
It’s a pain when you have a lot of labels but better than the pesky warning always showing up. You could probably create a regular expression to find matches as well but a quick find/replace is usually sufficient.