Hacking Your Keyboard in Software

At the start of this year (January 2013) I switched to a Dvorak keyboard layout. I have been slowly catching back up to my QWERTY speed. I decided to make the switch to be more ergonomic when typing. The last thing a software developer needs is a repetitive strain injury. One major pain point has been hitting the brackets ([, ]) keys; on QWERTY these are the (-, =) keys. As an iOS developer, you need to hit those keys all the time. I found myself having a hard time hitting these keys as I needed to stretch for them.

Read on →

TWTSideMenuViewController for iOS 7

One of the most common implementations of menu views has been the “Side Drawer”, “basement”, or “Side Menu” made popular in apps such as Facebook and Path. When someone taps the infamous “Hamburger” to open a side menu the main screen slides to the right (or left in some implementations) to reveal another screen below. This works well in iOS 6 and earlier because the status bar exists in a 20pt tall area that is isolated from the rest of the application. In iOS 7, the status bar is overlaid on the screen below it. What does it mean for sidebars or “basement” views in iOS 7?

Soon after iOS 7 was announced at WWDC in June, many designers on Dribbble started playing around with a new approach for doing these menus. Many came to a similar approach where the main screen would scale down and to the right.

Working with the team at Luvocracy, we were inspired by this approach and with a few ideas of our own we created TWTSideMenuViewController.

Read on →

UIAppearance for Fun and Profit

Building custom user interfaces is something our iOS development team encounters on a daily basis. Anything you can do to make it faster to develop or make your reusable controls easily customizable is an easy victory. UIAppearance gives you this easy victory.

While UIAppearance isn’t a brand new topic, it seems to get less love than it should. UIAppearance is a protocol available since iOS 5 that allows a developer to quickly configure the appearance of user interface controls provided by Apple. The fact that that your custom controls can take part in UIAppearance is talked about even less. This post will cover the basics of using UIAppearance and will explore adding support to your custom interface components.

UIAppearance Basics

You’ll be glad to know that UIAppearance is a straightforward API with almost no learning curve. To use it you need only know three things.

  • Properties and methods exposed to UIAppearance are decorated with the UI_APPEARANCE_SELECTOR attribute.
  • The class method +[UIControl appearance] will set the UIAppearance system to apply the specified properties when the control is created.
  • The class method +[UIControl appearanceWhenContainedIn:] will set the UIAppearance system to apply the specified properties when the control is created, but only when it is created in the specified containers.

That is all there is to it. UI_APPEARANCE_SELECTOR, + appearance, + appearanceWhenContainedIn:

Adding some style to UINavigationBar

Let’s see how this works. Say you want to style your UINavigationBar to be something a little different than the standard iOS style. First, look at the header file for UINavigationBar (you can find this by right-clicking on the symbol and choosing ‘Jump to Definition’ on it in Xcode).

Search for UI_APPEARANCE_SELECTOR. You’ll see it attached to many of the properties and methods, but not all. This is your guide to what is available by UIAppearance. In our case, the first time we see the attribute is with:

1
@property(nonatomic,retain) UIColor *tintColor UI_APPEARANCE_SELECTOR;

This means that the tintColor property is available for UIAppearance. This means I can now apply a global style affecting the tint to all UINavigationBar objects by telling the appearance proxy:

1
[[UINavigationBar appearance] setTintColor:[UIColor redColor]];

Now, no matter where a UINavigationBar is displayed within my app, it will be tinted red. Classy.

You can make this even more specific by telling the style to only apply when it is inside your own YOURCustomViewController. Consider the code:

1
2
[[UINavigationBar appearanceWhenContainedIn:[YOURCustomViewController class], nil]
                               setTintColor:[UIColor redColor]];

You’ve now told it to only apply the red tint color when a UINavigationBar is displayed inside a YOURCustomViewController. However, if I add a UINavigationBar to another view controller, it will not be tinted red. Only in the case that an instance of a UINavigationBar is in the hierarchy below an instance of a YOURCustomViewController will it be tinted red. Still classy.

All of these appearance styles can be applied as early as you like in your application. For example, you can set all your styles in -[UIApplicationDelegate application:didFinishLaunchingWithOptions:].

Supporting different iOS versions

As can often occur when working with any API, certain versions of can provide different functionality. How can we build an application level style when the available methods and properties on Apple’s controls are changing?

Thankfully, Objective-C is a dynamic language that allows runtime introspection on your objects. In a similar style to how you would ask your object if it -respondsToSelector:, you can ask a class if it’s instances respond to a method as well.

Consider this sample:

1
2
3
if ([UINavigationBar instancesRespondToSelector:@selector(setShadowImage:)]) {
    [[UINavigationBar appearance] setShadowImage:awesomeShadow];
}

The shadowImage property is new to iOS 6. Using +[NSObject instancesRespondToSelector:, we can inspect whether any instance of an object of this type will respond to this selector. Since you’ll be using the class type to apply an appearance, not an instance, this class method will tell you if this property can be used.

Using UIAppearance in your custom UI views

As stated earlier, you too can take advantage of UIAppearance in your custom views. Following the same pattern as seen above, let’s create a UIButton subclass that provides a property through UIAppearance.

I want to expose the font of the label on a UIButton. After subclassing, I’ll create a property that is decorated with `UI_APPEARANCE_SELECTOR called titleFont.

1
2
3
4
5
@interface TWTButton : UIButton

@property (nonatomic, strong) UIFont *titleFont UI_APPEARANCE_SELECTOR;

@end

Next, I create the setter implementation and set the title label’s font property.

1
2
3
4
5
6
7
8
9
10
11
12
13
#import "TWTButton.h"

@implementation TWTButton

- (void)setTitleFont:(UIFont *)titleFont
{
    if (_titleFont != titleFont) {
        _titleFont = titleFont;
        [self.titleLabel setFont:_titleFont];
    }
}

@end

Now, you can set its appearance as if it was always available via UIAppearance:

1
[[TWTButton appearance] setTitleFont:myFont];

For a more detailed example of this, check out TWTButton.


Android Helpers

Java helpers are simply classes that work can be delegated to. There is no difference in Android applications. Keeping helper classes small, tight and focused can improve your app. Here are some advantages:

  • Enforce framework requirements in a concise way.
  • Wrap platform differences
  • Keep your code DRY

First things first. Create a class with a private constructor. That will prevent accidental instantiation of the helper class. For our purposes, the helper class will simply be a collection of public static methods.

1
2
3
public class ExternalStorageHelper {
  private ExternalStorageHelper() {}
}

Enforce framework requirements

Let’s use Android’s external storage as an example for building a helper class. Before working with external storage, getExternalStorageState() should be called to check it’s availability. The call returns a String and checking the value can be a little ceremonial. It might be cleaner just to ask the boolean question you care about.

The method isExternalStorageMounted() shows that you can ask that simple question to test for the required availability.

1
2
3
public static boolean isExternalStorageMounted() {
  return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}

In a recent tweet, Romain Guy reminded developers to put data in the right place on external storage. Your app might benefit from the media scanner by placing files in the correct location. A helper method can enforce this and you only have to remember the details once. Here, music files can be directed to appropriate directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static File openMusicDirectory(Context context) {
  if (isExternalStorageMounted()) {
      return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) ?
          context.getExternalFilesDir(Environment.DIRECTORY_MUSIC) :
          openDirectory("music");
  }
  return null;
}

private static File openDirectory(String dirname) {
  File f = null;
  if (isExternalStorageMounted()) {
      File storageDir = Environment.getExternalStorageDirectory();
      f = new File(storageDir, dirname);
      if (f != null && !f.exists()) {
          f.mkdirs();
      }
  }
  return f;
}

Wrap platform differences

Prior to API 8, files were written using getExternalStorageDirectory(). Beginning with API 8, getExternalFilesDir() is used with a type parameter to enable the media scanner to properly categorize files.

You can make your application’s files available for sharing. In openPublicPicturesDirectory(), we use the required directory to share images that will not be deleted with the application. Despite the runtime API level, the files will be saved in a sharable, public directory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static File openPublicPicturesDirectory() {
  if (isExternalStorageMounted()) {
      return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) ?
          Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) :
          openPublicDirectory("Pictures");
  }
  return null;
}

private static File openPublicDirectory(String dirname) {
  File f = null;
  if (isExternalStorageMounted()) {
      File storageDir = Environment.getExternalStorageDirectory();
      f = new File(storageDir, dirname);
      if (f != null && !f.exists()) {
          f.mkdirs();
      }
  }
  return f;
}

Another example, getCacheDir(), also shows this ability to wrap platform differences. The cache directory is a useful location to temporarily persist files. If external storage is not mounted, we fallback to the device internal memory using Context.getCacheDir().

1
2
3
4
5
6
7
8
9
10
11
12
13
public static File getCacheDir(Context context) {
  return isExternalStorageMounted() ? getExternalCacheDir(context) : getCacheDirByContext(context);
}

private static File getExternalCacheDir(Context context) {
  return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) ?
          context.getExternalCacheDir() :
          context.getCacheDir();
}

private static File getCacheDirByContext(Context context) {
  return context.getCacheDir();
}

If external storage is available, it will use it, provided the device is running API 8 or higher. Otherwise, it will fallback to internal memory as before.

Keep your code DRY

These are small methods. Even so, copying and pasting little snippets throughout your app is a code smell. The helper is just enough context to wrap reusable functionality.

There are some legit objections to helper functions, especially when they are used as a dumping ground for unrelated functionality. They can resist refactoring since they aren’t in front of you all the time like the classes that call them. So keep it small and focus on your application’s needs. There’s no need to construct a generic library for everything. So, rewrite your helpers for each application if you want. That way you’re not locked into a strict library pattern of error or exception handling. Let your app be your guide.

It’s a little convenience that keeps your code clean and your head free of low level framework details.


Automated Automation Testing With Calabash

We are constantly looking for new processes and tools to help us create apps quickly and more efficiently. Testing the applications we create is an important part of this. Calabash is a tool based on Cucumber for doing Acceptance testing with iOS and Android apps. This is a great way to automate testing of the user interface of an application.

Here is a talk I gave at a CocoaHeads Raleigh-Durham event earlier this year and at the latest CocoaConf Raleigh:


Be Careful Using NSNotificationCenter With Blocks

NSNotificationCenter is a long existing mechanism for broadcasting messages to zero or many listeners. Many of Apple’s frameworks work deeply by notifiying you via an NSNotification when a message is posted. Traditionally, the workflow has been to follow a pattern similar to this:

Simple Receiving Notification Sample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someMethod:) name:kMyNotificationIdentifier object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)someMethod:(NSNotification *)note
{
    // Message received
}

Blocks!

As of iOS 4 and the introduction of blocks, Mac and iOS developers can now use blocks to subscribe to NSNotification broadcasts. This new method also allows you to specify an NSOperationQueue to perform the block action on.

Block-based NSNotificationCenter
1
2
3
4
5
6
7
- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserverForName:kMyNotificationIdentifier object:nil queue:nil usingBlock:^(NSNotification *note) {
        // message received
    }];
}

Wait, what?

Not so fast! Who is the observer? What removes this observer? What if you load several view controllers that do this? This block based method is not as simple as it appears. Reading the docs, we learn that addObserverForName:object:queue:usingBlock: actually returns an opaque observer that you are meant to retain, and subsequently -removeObserver with. Let’s take a look at what this looks like.

Block-based NSNotificationCenter Properly
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@implementation MyViewController
{
    id _notificationObserver;
}

// ...

- (void)viewDidLoad
{
    [super viewDidLoad];
    _notificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kMyNotificationIdentifier object:nil queue:nil usingBlock:^(NSNotification *note) {
        // message received
    }];
}

// dealloc, or potentially a method popping this view from the stack
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:_notificationObserver];
}

As you can see, you still need to track the observer of a notification and remove it. Similar to what you would do if you were using the selector-based notification listener. Oddly enough, this is an example of a block-based API not really improving things. For this API, the selector-based NSNotificationCenter listener is a much simpler option as you don’t have to maintain the observer seperately.


Video: Git Bisect

Finding bugs in your iOS or Mac project can be difficult. Use a tool provided by git called ‘git bisect’ to help find where a bug started in your application. It does a binary search to find the commit that introduced the bug.

To find out more information visit the git bisect manual page.


Introducing TTAlertView

TTAlertView is a drop-in replacement for UIAlertView that allows the developer to customize the presentation of an alert. TTAlertView uses the familiar interface of UIAlertView, so you don’t have to worry about rewriting any of your code – just drop it in, add some assets, and -bam!- you have a unique, customized alert view for your app!

Read on →

Horizontal Image Scroller for Android

HorizontalImageScroller-Android is a UI widget library for Android that will let your users scroll through a horizontal list of images, and let you implement it without breaking a sweat.

Read on →

Video: Foundation Collections

Several of us at Two Toasters are involved at local CocoaHeads meetups. We meet with other iOS and Mac developers to share beer, pizza, and knowledge. The big draw is a series of Keynote presentations. Topics range from Cocoa basics and new SDK features to arcane Core Foundation behavior.

Here’s a talk I gave this summer about Foundation’s lesser-known collection classes.

If you found this valuable, consider a local meetup group. Ours is CocoaHeads RTP, and we’d love to see you. If you’re remote, antisocial, or allergic to pizza, you can watch more of these videos at cocoaheads.tv.