May 12, 2009

Multiple Buttons on a Navigation Bar

Previously, I wrote about how to use standard icons in your navigation bar. This takes advantage of the nav bar's ability to put a button on the right side. But what if you want to put multiple buttons there? If your title is short enough, you can easily fit 2 or 3 buttons in that space. The nav bar allows you to stick content on the right hand side via the rightBarButtonItem property. On the surface, you might think you can add but one button to this property. But it's not so. There is an initializer for UIBarButtonItem that takes a view:
initWithCustomView:(UIView *)customView
With this, you can create multiple UIButton objects, add them to a UIView, and then create a UIBarButtonItem passing in this parent UIView. The following pseudo-code shows what I mean:
// create the container
UIView* container = [[UIView alloc] init];

// create a button and add it to the container
UIButton* button = [[UIButton alloc] init...];
[container addSubview:button];
[button release];

// add another button
button = [[UIButton alloc] init...];
[container addSubview:button];
[button release];

// now create a Bar button item
UIBarButtonItem* item = [[UIBarButtonItem alloc] initWithCustomView:container];

// set the nav bar's right button item
self.navigationItem.rightBarButtonItem = item;
[item release];

But, what if you want multiple *standard* buttons. Access to the standard buttons/icons is through the UIBarButtonItem class, not UIButton. You can't add UIBarButtonItem objects to a UIView. While there is support to create a UIBarButtonItem object from a UIView-derived object, there does not seem to be a way to do the opposite; there is no way to create a UIView object from a UIBarButtonItem. The only way I found how to deal with multiple UIBarButtonItem objects is to stick them in a toolbar. A UIToolBar is designed to hold multiple UIBarButtonItem objects. Think of a toolbar as your container, instead of the UIView object. And since a UIToolBar is UIView based, it can be added to the right side of a nav bar using the above trick. The following code shows how you can add two standard buttons to the right side:

// create a toolbar to have two buttons in the right
UIToolbar* tools = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 133, 44.01)];

// create the array to hold the buttons, which then gets added to the toolbar
NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:3];

// create a standard "add" button
UIBarButtonItem* bi = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:NULL];
bi.style = UIBarButtonItemStyleBordered;
[buttons addObject:bi];
[bi release];

// create a spacer
bi = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
[buttons addObject:bi];
[bi release];

// create a standard "refresh" button
bi = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refresh:)];
bi.style = UIBarButtonItemStyleBordered;
[buttons addObject:bi];
[bi release];

// stick the buttons in the toolbar
[tools setItems:buttons animated:NO];

[buttons release];

// and put the toolbar in the nav bar
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:tools];
[tools release];


May 6, 2009

Reflection in Objective-C

When I first learned Java, I thought the whole reflection package was novel, and it put Java closer to the realm of interpreted scripting language and farther away from the then-mainstream languages of C and C++. The idea of being able to look inward at the class metadata of an object at runtime was really fascinating, although not always terribly useful in everyday application programming. Those programmers coming over to the Objective-C world from Java will be happy to know that Objective-C also supports the concepts of reflection, AKA introspection. In fact, Objective-C 2.0 has many runtime features such as dynamically changing a class definition and even creating a new class dynamically. The necessity for these abilities is rather obscure, and it firms my belief that Objective-C is a ridiculously bloated language. To me, Objective-C has a bit of an identity crisis: it's not quite sure if it's an interpreted language or a compiled language. The runtime is mostly dynamic. Unlike C++, Objective-C does runtime binding. This is why you can do things like define methods for an implementation that are never declared in your header file, or extend existing classes with categories. Unfortunately, because of all this bloat, it is hard to find just the simple stuff that you might actually use in your day-to-day code. I will try to unearth some of these jewels and bring them to light.

Grandpa NSObject

Most, if not all, the runtime reflection support comes from the NSObject class. NSObject, like Java's Object class, is the granddaddy class of all classes (except for some rare exceptions). Therefore, all of your classes already have access to this reflection support. It's important to note that all this reflection support is not part of the Objective-C language per se; it is part of the NS* runtime environment. This is also why some of this stuff seems tacked on. It's because it has, uh, been tacked on.

Getting Class Metadata

You can access the class metadata for an object by calling the class method:

Class c = [self class];

This method is both an instance and a class method. It returns a C struct full of all sorts of mysterious stuff, like the list of instance variables, methods, etc. All of this is old hat to the java.lang.reflect package users out there, but the interfaces to reach this stuff in Objective-C seems really complex. This is probably difficult by design to keep the riff-raff out. So far, the only use I have for the class method is to provide the parameter to the isKindOfClass method described below. I never need to actually look at the contents of the Class structure.

Dynamic Method Invocation

I already discussed one aspect of reflection in my article about invoking methods. This allows you to build up a method call, arguments and all, at runtime. This is similar to using the java.lang.reflect.Method class in Java.

Testing inheritance

Java has an operator called instanceof that allows you to check if a object is an instance of a particular class or interface. Objective-C has a similar feature, the isKindOfClass: method. isKindOfClass: will return YES if the receiver is an instance of the given class or an instance of any class derived from the class. For example, if I had an array of related pointers, I can operate on each differently according to its type:

for(BaseClass* base in myArray) {
 if([base isKindOfClass:[ClassOne class]]) {
     // do stuff specific to ClassOne
 }
 else if([base isKindOfClass:[ClassTwo class]]) {
     // do stuff specific to ClassTwo
 }
 else if([base isKindOfClass:[ClassThree class]]) {
     // do stuff specific to ClassThree
 }
 // etc
}

If you want an exact class match, and not match any inheriting classes, then you use isMemberOfClass:.

Testing Protocol Conformance

Similar to class instance testing, you can also test whether an object conforms to a particular protocol. Java neatly uses instanceof for both classes and interfaces, but Objective-C has to have a more clunkier approach. To test conformance, use the conformsToProtocol: method:

BOOL conforms = [obj conformsToProtocol:@protocol(MyInterface)];

Testing for Method Existence

To an old Java and C++ hack like me, it seems extremely odd that you may not know if an object implements a method or not. But since Objective-C classes are largely dynamic, you need a way to check if a method you need is actually there. Hence the method respondsToSelector:. Here you are asking the receiver if it implements (or inherits) the given method:

if([obj respondsToSelector:@selector(aMethod:)]) {
   // it's there, so we can call it
   [obj aMethod:YES];
}

Certainly, there is way more you can do on the reflection front in Objective-C, but I tried to discuss the more commonly used reflection mechanisms. If you need too add hardcore dynamic nature to your software, you should be familliar with these documents: Runtime Programming Guide: Introduction Runtime Reference

May 4, 2009

Using Standard Toolbar and Navbar Buttons

In an article several months back, I discussed how to use standard Tab bar buttons. These are icons provided by Apple for you to use in the tab bar. But tab bars are not the only container that offers system-provided icons. There are standard icons available for toolbars and navigation bars. Recently I wanted to make use of a system icon, but it took me some time to find what icons were standard and how to use them. Even though it is fairly trivial, I would like to share this information, if nothing else but to save people a few minutes of needless searching. If you feel weird about using system-provided icons, don't. Apple is very keen on developers making use of the standard icons and encourages it in the HIG. However, Apple is also adamant about the consistent use of these icons. If your application uses a standard icon in a way unintended for that icon, then it is likely your app will get rejected from the app store. For example, if you are using the standard Contacts icon to bring up a list of contact lens providers, ding! Here is the section in the HIG that lists the standard icons and their intended uses. This gives you an idea to what is available, but doesn't help you coding one of them up. You have to know how to reference each of these in your code. For this, you have to look at the UIBarButtonItem class reference. If you go to the Constants section, you will see the UIBarButtonSystemItem enumerations which define the values for all the system icons.

For nav bars

To put a system icon on the navigation bar, you have several choices for the location. At the most basic level, you can put the icon on the left or the right. If you require more refinement, it's quite easy to do with subviews, but that technique is well-documented and outside the scope of this article. Here is the simple code for putting the standard refresh icon in the left position:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
                                      initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                                      target:self
                                      action:@selector(refresh:)];

The first parameter is the enum from the UIBarButtonItem reference. The target/action parameters specify the method to call when the button is hit.

For toolbars

Adding the standard icons to a toolbar is a little more involved, but still straight-forward. Toolbars also take UIBarButtonItem objects, but instead of assigning them to specific locations, you must add them to an NSArray object first (in the order you want them) and then add the array to the toolbar object.

// create the toolbar object
UIToolBar* toolbar = [[UIToolBar alloc] init];

// create an array to hold the buttons
NSMutableArray* buttons = [[NSMutableArray alloc] init];

// create a standard button
UIBarButtonItem* button = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
target:self
action:@selector(refresh:)];

// stick it in the array
[buttons addObject:button];

// add more buttons
//...

// add the array to the toolbar
toolbar.items = buttons;

// done with the buttons array
[buttons release];