Tag Archives: iOS

Design decisions behind Haneke 1.0

My iOS image caching library Haneke will soon reach version 1.0.0, which by Semantic Versioning means that Haneke will leave initial development and have a stable API.

Haneke 1.0 is a major refactoring with API changes and improvements on all fronts. At the time of writing this the new version sits in its own pull request, awaiting pre-release feedback before being merged into master. Whereas the pull request acts as a changelog, this post gives me an opportunity to comment on two of the most important design decisions of the refactoring.

Leaner UIKit categories

The entry point to Haneke is it UIImageView category. It allows to load images from network or disk with one line of code, leveraging the full power of image caching and automatic resizing in the process. Before 1.0, the UIImageView category had 4 responsibilities:

  • Loading images from network or disk
  • Determining the image size and aspect ratio based on the view properties
  • Interfacing with the cache
  • Displaying images

Of those, only determining the image properties and displaying images are specific to UIImageView. When users of the library started asking for a similar category for UIButton (none more enthusiastic than Aleix Ventayol), it became clear that the rest of the code could be reused.

My first instinct was to create a UIView category and move the code there. This was a step in the right direction, and such category now exists in version 1.0, mostly for helper code that interfaces with the cache. However, loading images from network or disk is a common need for any client of the cache, no matter if it’s a UIKit view or not. Shouldn’t this responsibility be independent of the presentation layer? And where should it be?

Turns out an early design decision was the answer. Haneke had the concept of cache entities since its inception, where an entity represents an image-key pair whose image will be requested only if needed. When an image is not available in the cache in the required format (size, aspect ratio and other transformations), the cache will ask the corresponding entity to provide the original image. Providing the original image is assumed to be an expensive operation (in memory and performance), so entities help to make sure this is done when absolutely needed.

Loading images from network and disk are in fact particularizations of providing the original image. The cache entity behavior is simply a protocol, but by creating concrete implementations that know how to load an image from an URL or path two reusable components were born: HNKNetworkEntity and HNKDiskEntity. And the UIImageView category went from about 400 lines of code to about 150, a great deal of which are convenience methods.

A standalone disk cache

I tend to design Objective-C libraries to use as less files as possible, often grouping many classes in the same .m file. This improves library usability (nothing beats dragging a single header-implementation pair to play with something) at the expense of ease of the development (modifying longer files can be daunting). Haneke initially was one of those single file libraries, a thousand line class with helpers.

When reimagining Haneke for Swift with Luis Ascorbe, Oriol Blanc and Joan Romano we didn’t start with this constraint because Swift supports frameworks, and the number of files in a library becomes less important. Also, it would have been an early optimization to be concerned about file modularity. Naturally, each responsibility became its own class, and one of those is DiskCache, the Swift class for the disk cache.

Going back to Haneke for Objective-C, previous to version 1.0 the HNKCache class was responsible for both managing both the memory and disk cache. Haneke is an image cache, and there are optimizations at memory level that are specific to images. At disk level, though, there’s nothing special about how Haneke reads and writes files. This meant that a generic-purpose least-recently-used disk cache was hidden inside HNKCache, which became evident while developing the Swift version. So was born HNKDiskCache.

HNKDiskCache sets and fetches data from disk, and doesn’t have any dependencies to the rest of Haneke. Of course, it was designed to serve Haneke’s needs, so its implementation has some quirks. All of its operations are performed asynchronously in a serial queue, which is public in case you need to wait for any of them to finish (a blessing for writing unit tests). Also, it has a somewhat odd enumeration method that loads all key-data pairs by descending access date. This is used by Haneke to preload images in memory, and I’m not sure it has any other use case.

Separating the disk cache into its own component also made the code easier to test and allowed me to greatly increase test coverage without resorting to white-box tests. Haneke 1.0 now is currently at 99% test coverage, with 200 hundred unit tests. While I do miss having a single file for the cache, I opted to put HNKDiskCache in its own file to reinforce its independency with the rest of Haneke and increase its discoverability. Here’s hoping that people who need a disk cache find it.

How to cache server responses in iOS apps

Apps that communicate with a server via HTTP usually have two particular requirements: don’t make the user wait for data whenever possible, and be useful when there is no internet connection. Both are the source of much reinventing the wheel.

These are very common problems, so it shouldn’t surprise us that iOS has all the APIs we need to implement response caching and offline mode. Very little code is required, even less if your server plays nice with cache headers and you’re targeting iOS 7 and above.

The shared NSURLCache

The shared NSURLCache gives us much out of the box. If our server uses Cache-Control HTTP headers a sets the maximum age for its responses, both the shared NSURLSession (iOS 7 only) and NSURLConnection will respect this and return cached responses before they expire. We don’t need to write any code to get this functionality, and in a perfect world we would stop here.

Sadly, the world of HTTP caching in iOS is far from perfect.

Offline mode

What happens if a response has expired and the app is offline?

By default, NSURLSession and NSURLConnection will not use an expired response if there isn’t internet connectivity. This is the behavior of NSURLRequestUseProtocolCachePolicy, the default value of - [NSURLRequest cachePolicy], which simply follows the HTTP protocol cache headers to its best of its knowledge.

In most cases, showing old data is better that showing no data (exceptions being weather and stock, for example). If we want our offline mode to always return the cached data, then our requests must have a different cache policy, one that uses cache data regardless of its expiration date. Both NSURLRequestReturnCacheDataDontLoad and NSURLRequestReturnCacheDataElseLoad fit this criteria. In particular, NSURLRequestReturnCacheDataElseLoad has the advantage of trying the network if no cached response is found.

Of course, we should only use these cache policies when there is no internet connectivity. If we have some reachability observer at hand, our code could look like this:

Then we give this request to NSURLSession or NSURLConnection and hope for the best.

But not if you´re targeting iOS 6. There is a bug in iOS 6 that prevents NSURLRequestReturnCacheDataDontLoad and NSURLRequestReturnCacheDataElseLoad from working properly. If you’re targetting this version and want to implement a true offline mode you’ll have to read NSURLCache directly:

Offline mode using AFNetworking

The most excellent AFNetworking 2.0 library offers HTTP requests managers in AFHTTPSessionManager (using NSURLSession) and AFHTTPRequestOperationManager (using NSURLConnection). Both can be customised by subclassing them and overriding the method that creates the data task or operation respectively.

Subclassing AFHTTPSessionManager to modify the cache policy of URL requests can be done by overriding dataTaskWithRequest:completionHandler::

Likewise, with AFHTTPRequestOperationManager:

Note that in both cases we’re using AFNetworkReachabilityManager as our reachability observer instead of implementing our own. Another advantage of using AFNetworking.

AFNetworking does not provide a workaround for the iOS 6 bug mentioned above and most likely never will. We still have to read the cache directly if our app targets iOS 6 and want to use the mentioned cache policies.

Forcing response caching

What happens if the server doesn’t set cache headers?

Good server APIs are few and scarce, and a consistent use of cache headers is not always a given. Even if we don’t have any say on the server cache policy, we can still set the expiration date of responses by adding or replacing cache headers at client level. This should only be used as a last resort, when it’s impossible to reach or convince backend developers to add cache headers.

Forcing response caching with NSURLSession

The NSURLSession delegate receives a URLSession:dataTask:willCacheResponse:completionHandler:, as part of the NSURLSessionDataDelegate protocol. This provides a great opportunity to modify the response before caching it. If our server doesn’t provide cache headers and we’re confident it should, we can add them like this:

Forcing response caching with NSURLConnection

Likewise, the NSURLConnection delegate receives a connection:willCacheResponse:, as part of the NSURLConnectionDataDelegate protocol. The code to modify the response headers right before caching the response would be something like this:

Forcing response caching using AFNetworking

When using AFNetworking the code is slightly different depending on which HTTP manager we’re using. AFHTTPSessionManager acts as the NSURLSession delegate, so we simply implement URLSession:dataTask:willCacheResponse:completionHandler: in our subclass and call super as required by the AFNetworking documentation.

In the case of AFHTTPRequestOperationManager, AFHTTPRequestOperation has a handy block setter for connection:willCacheResponse:. This allows us to put all our cache code in the HTTPRequestOperationWithRequest:success:failure override:

Additional considerations

NSURLCache caches responses, not the result of parsing them. Complex responses might require considerable parsing time, and in those cases it might be best to cache the parsed objects in a custom cache instead of relying on NSURLCache.

Additionally, you might want to validate the response before caching it. Servers are prone to sporadically return errors (e.g., “Too many connections”), and caching such a response would make sure the user gets the same error for as long as the response doesn’t expire.

Further reading

NSNotificationCenter part 4: Asynchronous notifications with NSNotificationQueue

This article is the fourth part of a series about NSNotificationCenter. Head over part 1 for the basics of receiving and sending notifications.

Notifications are synchronous by default, meaning that the object that posts a notification must wait until the notification center dispatches the notification to all observers and each of them handles it before it can resume its execution. This might be inconvenient for objects that post frequent notifications (e.g., a UI component that notifies on every touch movement), and Foundation offers mechanisms to coalesce and delay notification via NSNotificationQueue.

NSNotificationQueue is a buffer of notifications that handles when to post them based on given criteria and the run loop, in a FIFO fashion. Each thread has a default notification queue via defaultQueue.

A word of warning

The NSNotificationQueue documentation appears to be in a state of flux after a OS X release note that basically discourages its use. From the release note:

NSNotificationQueue is an API and mechanism related to run loops (NSRunLoop), and the running of run loops. In particular, posting of notifications via the notification queue is driven by the running of its associated run loop. However, there is no definition for what run loop a notification queue uses, and there is no way for a client to configure that. In fact, any given notification queue might be “tickled” into posting by nearly any run loop and different ones at different times (and given that enqueued notifications are also mode-specific, what mode(s) the run loop(s) are running in any any given time also come into play). Further, although each notification queue is “thread-specific” (see the +defaultQueue documentation), there has never been any relationship between that thread and the run loop used by a notification queue. This is all more and more problematic as more and more things move to happening on different and new threads.

The practical upshot is:

  • Notifications posted through a queue might not be posted in any particular “timely” fashion;
  • Notifications posted through a queue might not ever be posted (the run loop of the thread that the queue chose to ask to poke it might not be run again; for example, the thread of that run loop might exit and the notification queue discarded);
  • Notifications can be posted by any given queue on a different thread than the thread the queue is the default queue for (when a queue is a default queue for some thread);
  • Notifications can be posted by any given queue on different threads over time;
  • There is no necessary/guaranteed relationship between the thread(s) on which notifications are enqueued and those on which the notifications eventually get posted (delivered) for any notification queue

This is true for all releases of OS X. Foundation and AppKit do not use NSNotificationQueue themselves, partly for these reasons.

Taking this into account, and until Apple clarifies their stance on this class, you shouldn’t assume that notifications posted with NSNotificationQueue will ever be posted, or received in any particular thread.

Delaying and Coalescing notifications

NSNotificationQueue‘s enqueueNotification:postingStyle: is used to post a notification asynchronously. Unlike NSNotificationCenter‘s postNotification: and its convenience methods, it immediately returns to the invoking object after putting the notification in the queue. The delay will depend of the given posting style. There are three options:

  • NSPostNow: The notification will be posted synchronously. If not used with coalescing, this would be exactly the same as postNotification:.
  • NSPostASAP: The notification will be posted when the current iteration of the run loop completes, much like a zero-delay timer (credit to Mike Ask for the analogy).
  • NSPostWhenIdle: The notification will be posted when the run loop is in a wait state or idle. This is handy for notifications that are not very important.

An example:

Delayed notifications are most useful when combined with coalescing, as the object creating the notifications might queue more before the first one is posted. By default, notifications queued with enqueueNotification:postingStyle: are coalesced by both the notification name and sender. The result is that when a notification is posted, it is the first notification queued for the corresponding name and sender; the rest have been coalesced (discarded, in effect).

By coalescing notifications we can make sure that a single notification is posted for repeatable events (e.g., receiving fresh data from a socket). This can be further controlled with NSNotificationQueue‘s enqueueNotification:postingStyle:coalesceMask:forModes:, which expands the delay options covered above with a coalescing criteria. The options are:

  • NSNotificationNoCoalescing: Do not coalesce notifications in the queue.
  • NSNotificationCoalescingOnName: Coalesce notifications with the same name.
  • NSNotificationCoalescingOnSender: Coalesce notifications with the same object.

The coalesce mask is a bit mask that allows us to combine NSNotificationCoalescingOnName and NSNotificationCoalescingOnSender to obtain the default behavior of enqueueNotification:postingStyle:.

Additionally, we can provide an array of run modes in which we want the notification to be posted. This typically will be nil, which is the equivalent to NSDefaultRunLoopMode. The following lines provide the same result:

Given that it is not possible to know exactly when the notification will be posted, the sender might be deallocated before its notifications are posted. A way around this is to dequeue the sender’s notifications before dealloc with dequeueNotificationsMatching:coalesceMask:.

Further reading

NSNotificationCenter part 3: Unit testing notifications with OCMock

This article is the third part of a series about NSNotificationCenter. Head over part 1 for the basics of receiving and sending notifications.

In order to avoid writing unit tests we are sometimes eager to declare our code as “untestable”. Like most code, notifications can be perfectly unit tested, and this is particularly straightforward with synchronous notifications, which are the most common kind.

Below we show how to test that synchronous notifications are posted (or not) and validate their userInfo with a little help from the superb Objective-C mocking framework OCMock. Finally, we share a few tips for unit testing observers.

For convenience, the code examples will not use STAssertNoThrow for exception failures.

Testing notification posting

OCMock provides an observer mock. This can be used to test that a particular method posts a particular notification, with the only requirement being knowing the name of the notification. A notification test requires a handful of lines of code:

First we register the observer mock for a specific notification and sender using a category extension provided by OCMock. Then, we tell the mock object to expect the notification from the sender. Since notifications are synchronous by default, right after we call the code that posts the notification we can simply verify the mock object. If the notification was received the observer mock will pass verification, otherwise it will fail.

Finally, like any other observer, once we’re no longer interested in the notification we remove it from `NSNotificationCenter.

Testing unwanted notifications

Some methods might post a notification only if certain conditions are met. A good test suite would also test that the notification is not sent if the conditions are not met. Luckily, the default behavior of the mock observer provided by OCMock is to raise an exception when an unexpected notification is received. The code to test this case is even simpler:

Validating userInfo

When the notification is expected to include specific userInfo keys we should also test that their values are correct. Again, OCMock comes to the rescue:

This is exactly the same than the first unit test example expect for a block that validates the userInfo property, passed using OCMock’s checkWithBlock: method.

Testing the observer

NSNoticationCenter calls observers by a given selector. For unit testing purposes, this selector is part of the public API of the observer class and as such should be included in the test suite.

To test the observer selector we will most likely need to provide it a notification parameter. While NSNotification is not meant to be initialized directly, we can use its static methods notificationWithName:object: and notificationWithName:object:userInfo: to create the notification. Alternatively, we can create a mock notification with OCMock.

Further reading

NSNotificationCenter part 2: Implementing the observer pattern with notifications

This article is the second part of a series about NSNotificationCenter. The previous part covers the basics of receiving and sending notifications.

If you ever tried implementing the observer pattern in Objective-C you might have noticed the need of using a non-retaining collection for the observers to avoid retain cycles, among other caveats.

Instead of writing your own custom observer implementation, a much leaner approach is using NSNotificationCenter. We could of course use it directly, but we would lose the strong typing expected from the observer pattern. Here’s how to implement this popular pattern with NSNotificationCenter at its core.

Typed observer

First, we define the observer protocol. In this example we will observe a custom audio player (HPEAudioPlayer):

Each observer method will correspond to a notification, hence the single notification parameter. The observer will not need to know the notification name; this will be an implementation detail.

Then, we add methods in our observable class to add and remove observers.

In the implementation of our observable class we define constants for the notification names:

Adding and removing the observer is reduced to calling NSNotificationCenter with the appropriate filters:

Finally, notifying the observers is as simple as posting the corresponding notification. NSNotificationCenter will take care of the rest.

Typed parameters with categories

When using the observer pattern one would expect the notification methods to have well-defined and typed parameters. Unfortunately, in the example above we’re using a generic NSNotification as our single parameter. What is the object? What is inside userInfo? We can do slightly better by using a category on NSNotification to explicitly answer these questions.

For our audio player example, we could have the following category:

By using these category methods the observer does not need to worry about casting the object property and doesn’t need to know the keys of the userInfo dictionary, or use it at all. Note that the additional properties are readonly, as NSNotification objects are expected to be immutable.

The category approach has still a problem, which is that the observer must know which category methods are available for each notification method (e.g., hpe_endTime is not defined for audioPlayerDidStartPlackback:). This can be solved by subclassing NSNotification.

Typed parameters with subclassing

Subclassing NSNotification allows us to provide a fully typed observer, including parameters, by giving each notification method its own notification subclass. Our observer protocol becomes:

As indicated in part 1, NSNotification is a class cluster that throws an exception if init is called. The implementation of its subclasses requires a few lines of boilerplate code:

Again, note that the properties are readonly to keep the notifications immutable.

The subclassing approach allows us to provide a fully typed observer at the expense of creating one class per method and dealing with NSNotification subclassing quirks. If strict typing is not required, the category approach is also valid as long as the parameters of each method are properly documented.

Further reading

NSNotificationCenter part 1: Receiving and sending notifications

Perhaps because it’s often paired with the much maligned KVO, or because the delegate pattern is so ubiquitous, NSNotificationCenter is frequently overlooked and misunderstood. Yet when it comes to broadcasting notifications to any object willing to listen, NSNotificationCenter has all your bases covered, and does so with a minimal number of methods and classes.

If you ever found yourself bubbling up events via delegates, pondering on how to avoid retain cycles when implementing the observer pattern, or working around blocks to deal with users leaving and then returning to a new UIViewController instance, chances are there was a much cleaner, decoupled solution using notifications.

This article is the first part of a series about NSNotificationCenter. Part 1 covers how to receive and send notifications while addressing common misconceptions. Part 2 provides a typed implementation of the observer pattern with notifications. Part 3 shows how to unit test notifications with a little help from OCMock. Part 4 deals with asynchronous notifications using NSNotificationQueue. Finally, a list of all public notifications in iOS and OS X are included as annexes.

While iOS classes will be used for examples, everything applies to OS X as well.

Notifications classes

Foundation provides 3 classes to deal with all your notification needs:

  • NSNotification: represents a notification.
  • NSNotificationCenter: broadcasts notifications and manages observers. Each app has a default notification center via defaultCenter.
  • NSNotificationQueue: coalesces and delays notifications. Each thread has a default notification queue via defaultQueue.

OS X offers a fourth class called NSDistributedNotificationCenter for communication between processes. We will not cover this class in this series.

Receiving notifications

To receive a notification you only need to know its name. Cocoa and Cocoa Touch are full of interesting and descriptively named notifications such as UIKeyboardWillShowNotification and UIApplicationDidReceiveMemoryWarningNotification. There are 165 public notifications in iOS 7.0 (annex A) and 393 in OS X 10.9 (annex B). Later we will see how to create your own notifications as well.

Receiving a notification takes very little code. Say you want to receive a memory warning (UIApplicationDidReceiveMemoryWarningNotification) outside a UIViewController, to clear a cache of some object. This is how it could look:

Adding the observer

The object that receives notifications is called observer, and must be added to a NSNotificationCenter. Unless you have a very strong reason not to, that will always be the defaultCenter.

init and viewDidLoad and viewWillAppear: in UIViewController are good candidates for adding observers. You should add the observer as late as possible and remove it as soon as possible to improve performance and avoid undesired side effects.

Observers register to a specific notification by specifying the name of the notification (usually a constant) and the sender of the notification as filters. Both are optional; in the above example, we don’t care who the sender is so we pass nil.

Specifying the sender is useful when different instances are sending notifications of the same name (e.g., you might be interested in the UITextFieldTextDidChangeNotification of a specific UITextField). If no sender is provided, you will receive all notifications with the given name. If no notification name is specified, you will receive all notifications of the given sender.

Handling the notification

Observers will receive notifications until they are removed from the NSNotificationCenter. Each notification is sent once per addObserver call. If you are receiving more notifications than expected, it might be a sign that you added the observer more than once (e.g., this might happen if you register the observer for notifications in viewWillAppear and unregister it in dealloc).

NSNotificationCenter will call the selector provided in addObserver:selector:name:object: with a single argument of type NSNotification. The selector is called in the same thread in which the notification was posted. Typically this is the main thread, so only check if the selector is running in a different thread if the corresponding documentation says otherwise.

The NSNotification object is a box of chocolates. It comes with an object id which is usually the sender of the notification and an userInfo dictionary with additional information about the notification. For example:

Knowing the contents of this dictionary for a specific notification might require debugging or -god forbid- reading the documentation. Don’t assume that any particular key will be present unless told otherwise.

You can also handle notifications with blocks to make unit test enthusiasts cringe. The initial example becomes:

The queue parameter is for asynchronous notificaions and is explained in part 4.

Removing the observer

The observer must be removed eventually, and you should do it as soon as you don’t need the notifications anymore. This is at best right after receiving the notification (e.g., to update the UI after MPMoviePlayerPlaybackDidFinishNotification) or at worst in dealloc. If you forget to remove the observer, NSNotificationCenter might send a notification to a deallocated instance, causing shenanigans.

NSNotificationCenter provides two methods to remove observer. removeObserver: and removeObserver:name:object:. The former unregisters the observer for all notifications, and the latter does so for notifications of the given name and sender, either of which can be nil. While it might be tempting to simply call removeObserver:, this is a bad practice as you might be unregistering from notifications registered elsewhere (e.g., in a superclass, subclass or category). Try to be as specific as possible when removing the observer.

As shown above, you also need to remove the observer when using blocks. In this case the observer is the object returned by addObserverForName:object:queue:usingBlock:. With these block observers you can use the single parameter removeObserver: more comfortably.

Sending synchronous notifications

Notifications are great to broadcast events that might be of general interest, such as model changes, user actions or the status of background processes. Unlike the delegate pattern, notifications can be used to notify various stakeholders and add very little coupling (in most cases, the observer only needs to know the notification name).

Naming notifications

The first step in creating your own notification is choosing a unique name. The document Coding Guidelines for Cocoa suggests:

For example:

  • Good: @"HPEAudioPlayerDidStartPlaybackNotification"
  • Bad: @"didStartPlayback"

The notification name should be a public constant. This will allow you to change the name of the notification without requiring any changes in the observers.

Posting the notification

Each app has a default NSNotificationCenter instance that can be used to broadcast notifications. You can create the notification object yourself and post it, or use a couple of convenience methods that do this. If you don’t need to send any additional information, posting a notification is as simple as:

The object parameter is typically used to pass the object sending the notification, normally self. NSNotificationCenter will create a NSNotification object for the given name and the given sender, and no additional information.

The notification is then sent to every registered observer in no defined order. Notifications are posted synchronously, meaning that postNotification: and its convenience methods will not return until all observers have processed the notification. Additionally, observers will be called in the same thread in which the notification is posted. Unless you explicitly state otherwise, observers will expect this to be the main thread.

Consider a background operation that notifies progress periodically. We want to send the notification and continue with our operation as soon as possible, and notify the observers in the main thread. A way to do this is with dispatch queues:

Sending additional information

In most cases you will want to send additional information with the notification, such as the progress value in the example above. Notifications can have a dictionary with custom data called userInfo. NSNotifcationCenter offers a convenience method to post notifications with userInfo:

Again, you should define any userInfo keys as public constants.

Subclassing NSNotification

If the userInfo dictionary does not suit your needs or if you prefer typed atributes you can also subclass NSNotification, with a few caveats. NSNotification is a Cocoa class cluster, which is another way of calling an abstract class. In particular, it does not implement name, object and userInfo and throws an exception if you call init.

Because of these caveats, subclassing NSNotification is generally frowned upon and some developers prefer to use categories. Full examples of both approaches are provided in part 2 where we implement a typed observer with notifications.

When using your own NSNotification subclass, the convenience methods to post the notification are no good. You are responsible for creating the notification object, and provide the name, object and userInfo (if applicable) either in the subclass implementation or before calling postNotification:. For example:

Further reading

RMShapedImageView: A UIImageView subclass that ignores touches on transparent pixels

When using transparent PNG images in iOS development sometimes it’s useful to limit touches to where the image is not transparent.

Artwork from

You don’t want to interact with the bird if you touch the top left or bottom right corners.

For UIButton, there’s the most excellent OBShapedButton by Ole Begemann. At Robot Media we also needed this for UIImageView. After asking about this problem on StackOverflow and studying OBShapedButton, I decided to create RMShapedImageView and open-source it on GitHub.

RMShapedImageView is a UIImage subclass that overrides pointInside:withEvent:. This method is called to determine if a touch is inside the view. In our case, we only want to return YES if the corresponding pixels are not transparent (alpha > 0).

Usage

  1. Add RMShapedImageView.h and RMShapedImageView.m to your project.
  2. Replace your UIImageView with RMShapedImageView either in code or Interface Builder (by setting the Class of your UIImageView to RMShapedImageView).
  3. Profit! 

RMShapedImageView works with retina and non-retina images, as well as transformed views. It’s particularly useful is you’re using gesture recognisers. Currently supports only two content modes: UIViewContentModeScaleToFill and UIViewContentModeTopLeft. More will be added in time.

Configuration

Touches are inexact things and querying the alpha value of a single pixel might be too strict, even more so if the image is scaled down. Furthermore, if the image has shadows you might also want to ignore touches on them. RMShapedImageView has two configuration options to work around these problems:

  • shapedTransparentMaxAlpha: maximum alpha value that will be considered transparent. 0 by default.
  • shapedPixelTolerance: number of pixels around the point that will be examined. If at least one of them has alpha bigger than shapedTransparentMaxAlpha pointInside:withEvent: will return YES. 0 by default.

The project also includes a demo and bare-bones unit tests and is distributed under the Apache License 2.0. You’re more than welcome to fork it and improve.

App Store keywords checklist: 21 tips to work around Apple’s horrible search

App Store icon

Don’t you hate those articles about App Store marketing who basically tell you you need to build a great app*? Me too.

Here are 21 practical and actionable tips to get the most from your App Store keywords, with real examples from my Mac app Email Contacts Extractor, references and further resources.

Let’s see how many of these you know already.

Basic tips

All of these tips can be found in the documentation provided by Apple.

  1. You can only use up to 100 characters for keywords.[1]
  2. Each word in your app title and company name counts as a separate keyword.[2]
  3. The description does not count as keywords.[3]
  4. Separate keywords with commas.[1]
  5. Keyword changes require an update of the app binary.[1]
  6. Prefer specific keywords.[4] E.g., extractor is better than tool.
  7. Each keyword must be more than 2 characters.[1]
  8. Keywords that use offensive language or are trademarked or that reference another app’s name or company name, might cause your app to be rejected.[1] However, many product or brand names are accepted based on the context of the app, so try them if appropriate. E.g., gmail.

Intermediate tips

Improve your chances with these tips learned by trial and error.

  1. Separate keywords with “,” but not “, ” (no extra space) to save characters.
  2. Use single words keywords but not phrases (even if the iTunes Connect Guide says otherwise). Searches that are a combination of your keywords will display your app too. E.g., “extract,contacts” instead of “extract contacts“.
  3. Consider including plurals if the App Store does not recognise them. To test this, first submit your app without plurals and search your desired plurals. Then upload a new version with the plurals that are not recognised by the App Store.[5] E.g., addresses.
  4. Category names no longer count as keywords. In any case, only use a category name as keyword if your app is very popular within that category or if the category is not too crowded.[6]
  5. While it’s not possible to know which keywords are more frequent, it is possible to scrap the App Store for common words in app titles. The last list I found was compiled by AppsFire. You might want to avoid adding any of these as additional keywords.
  6. If your app is free, you don’t need to include free as a keyword, although you might still want to include it in the app title for marketing purposes.[7]

Advanced tips

You should follow these tips if you plan to make a living from your app.

  1. Different countries produce different search results. You can localize both your app title and keywords. You can also change the App Store country to test the results. On iPhone: open the App Store, select the Featured tab, scroll down to your account and tap, change country region. On Mac: open the App Store, selected the Featured tab, scroll down, tap on the country flag.
  2. While it’s not possible to know which search terms are related in the App Store, we can consider Google searches as an approximation. Use Google Keywords Tool (limited to mobile traffic and each desired country) and Google Trends (limited by country) for ideas. E.g., using this I found that “export“, “backup” and more frequently used than extract in the context of email contacts export.
  3. iTunes and the iOS App Store sometimes produce different results. Try both.
  4. Consider including common misspellings as keywords. E.g., adress.
  5. Consider using services that track your keywords ranking, such as AppCod.esMobileDevHQ and AppStoreRankings. Unfortunately I can’t endorse any as I haven’t used them yet.
  6. In-app purchase titles do not count as keywords anymore.[7]
  7. Keywords might be deactivated by the App Review team without letting you know (unverified).[8] Make sure you test them all after releasing the app.

Bear in mind that the above change every so often. If you found that any of the tips doesn’t work anymore, please leave a comment below.

This post was all about keywords. For a more generic introduction to App Store Optimisation (ASO), you might want to read apptamin’s checklist.

* (BTW, they’re right)


1. ^ a b c d e App Store Resource Center – Marketing Resources.
2. ^ iTunes Connect – Frequently Asked Questions > App Store.
3. ^ iTunes Connect – Frequently Asked Questions > Manage Your Applications.
4. ^ iTunes Connect Developer Guide – Best Practices.
5. ^ App Store Optimization (ASO): App Name And Keywords.
6. ^ Category names no longer work in App Store search on the device.
7. ^ a b New rules in App Store Search.
8. ^ “SEO Optimizing” Your App for iTunes – Part 4 (Additional Findings).

Don’t give out your iTunes Connect password so easily!

We iOS and Mac developers love our sales and download numbers.

We love them so much that we will gladly give our iTunes Connect password to any company that provides shinny graphs of them.

You know you love them.

You know you love them.

There’s absolutely no need to give out your main password to services like AppFigures, App Annie or Mopapp. I’m sure these companies mean well and invest heavily in protecting your information. Unfortunately, in order to extract the data from iTunes Connect they’re forced to store a (hopefully encrypted) copy of your password. And we already know how that might end, don’t we?

It’s simple and you probably know how to do it already. iTunes Connect supports having multiple users for the same account, with different roles. Within iTunes Connect, go to Manage Users and select iTunes Connect User.

iTunes Connect screenshot

Then provide a descriptive name and an email address which needs to be different from yours. Fortunately, you don’t event need to have a different email account. If you’re using Gmail, just add a + suffix to the local part of your email address. Like this:

johndoe+appfigures@gmail.com

iTunes Connect will accept this as a different email address and all emails will go your inbox.

Finally, select the Finance or Sales role (as needed) and skip all notifications. Apple will send an activation email to your email account (if you used the + suffix).

Before clicking on the activation link you need to logoff from iTunes Connect (or open it in a new browser). Provide a password (a new one, of course) and presto, now you have a shinny new iTunes Connect user with limited access to your account.

Give this user to the App Annies of the world. If anything goes south, you can simply remove it form iTunes Connect.