Archive for the ‘iPhone’ Category

Processing UIImagePickerController

The UIImagePickerController class has been the developer’s best friend and worst enemy since it’s introduction into the iPhone SDK in iOS 2.0. For those who have not used it, this class provides a way for an application to have the user select and return an image, whether it be existing from the device’s library or fresh from the camera; this image may then be included into the application in some manner. Today we are going to discuss a problem that is almost as common as the use of the class itself! I’m talking about memory warnings and crashes.

Images on Display

I think one of the most common issues stems from developers trying to do something akin to the following code:

- (void)someActionMethod {

  UIImagePickerController *controller = [[UIImagePickerController alloc] init];
  [controller setDelegate:self];
  [self presentModalViewController:controller animated:YES];
  [controller release];

}

- (void)imagePickerController:(UIImagePickerController *)picker
                    didFinishPickingMediaWithInfo:(NSDictionary *)info {

  [[picker parentViewController] dismissModalViewControllerAnimated:YES];
  UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
  [myImageView setImage:image];

}

Translated into plain text, “as soon as the user selects an image and we get a callback, display that image in some view and move on”.  Eek!  Most often (even on the high-powered iPhone 4), this will result in one of the two following behaviors:

  1. Your app will crash…hard.
  2. After the user dismisses the picker, you get a memory warning, and the view controller that presented the picker looks as though it has been reloaded from scratch (…because it has)

This will happen most often with images from the camera, but as images stored in the library get larger and larger you will see it happen there as well.  The issue is a combination of memory recovery behavior and processing power.

My Brain Hurts

The first thing many developers notice is the memory warning that arises in the console circa the time of the failure…and so they tend to focus on it.  Because it’s the only visual clue they have to start diagnostics from.  The memory warning is usually marked with a “Level=1″, which indicates it’s a warning and not critical or some other level.  Even when your application is running perfectly, you will likely still get these warnings every time you use an image picker…and that’s okay!  However, what the warning does signal to you is that the wrong choice of your next move will result in one of the two behaviors above.

On an iPhone 3GS, for example, the camera is 3 megapixel.  UIImagePickerController gives you the full image back when you retrieve it in the delegate callback (that’s 2048 x 1536 pixels)!  Storing this much image data in memory is one thing, but forcing your UI thread to try and do something with it will only spell disaster.  iOS will try to first free up as much memory as it can by releasing view controller objects (symptom #2).  If it is unsuccessful, dire circumstances await (symptom #1).

What’s the Right Move?

What you do with the image (display it, save it to disk, etc.) depends on your application.  But there are two universal truths about the image data that comes back:

  • The image SHOULD be scaled down
  • The processing MUST not be done on the main/UI thread

Scaling

There is a really great piece of useful code in the community that I cannot take credit for, but I will post here for convenience.  This code uses UIKit methods to resize and scale down an image.

- (void)useImage:(UIImage *)image {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  // Create a graphics image context
  CGSize newSize = CGSizeMake(320, 480);
  UIGraphicsBeginImageContext(newSize);
  // Tell the old image to draw in this new context, with the desired
  // new size
  [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
  // Get the new image from the context
  UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
  // End the context
  UIGraphicsEndImageContext();

  [userPhotoView setImage:newImage];

  [pool release];
}

Even if you intend to save the full image to disk and you want to display a preview, that preview should not be larger than the viewport of the device (320×480 or 640×960).  Forcing UIKit to scale the image for you at runtime with a call to setImage: is a bad plan.

Backround Threading

Many of you may have looked at the previous method and asked why an NSAutoreleasePool was created; that is because of the next step.  Even if you have the presence of mind to scale down your image before displaying it, if you try to do so on the main thread you will end up with the same results as if you had left that job up to iOS. Because of this, the scaling method we have written should be dispatched into a background thread, and our delegate method gets modified like so:

- (void)imagePickerController:(UIImagePickerController *)picker
                    didFinishPickingMediaWithInfo:(NSDictionary *)info {

  [[picker parentViewController] dismissModalViewControllerAnimated:YES];
  UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
  [NSThread detachNewThreadSelector:@selector(useImage:) toTarget:self withObject:image];

}

You may also want to consider popping up a progress dialog or something during the operation (Apple does this as well, try taking a picture for your contacts), as it can take a few seconds.

Conclusion

There, now we have a working example of how to properly handle picked images that we want to display in our applications.  Hopefully this will keep some of you from going bald too soon.

A Short Note About Modal Presentation

One of the most common design patterns used to transition from one view to another in iOS is the use of the modalViewController property of UIViewController.  New views are presented using the presentModalViewController:animated: method, and dismissed using the dismissModalViewControllerAnimated: method.  Presenting a new view as a modal view does a number of things that are not always obvious:

  • Creates a parent/child relationship between the two view controller objects
  • The new view controller object is retained by the parent
  • Displays the new view fullscreen (on iPhone), optionally in an animated fashion
  • If animated, the animation is taken from the UIModalTransitionStyle of the NEW view

I have highlighted the top two items because it is those two that lead to the primary issues of misuse with modal presentation: over retention and child dismissal.

Child Dismissal

Per the Apple documentation, “The parent view controller is responsible for dismissing the modal view controller it presented using the presentModalViewController:animated: method. If you call this method on the modal view controller itself, however, the modal view controller automatically forwards the message to its parent view controller.”

Apple has done the developer a disservice here by automatically correcting bad practice, but doing so doesn’t make it good practice.  Apple clearly states that presentation AND dismissal of modal views are the responsibility of the parent view controller.  dismissModalViewControllerAnimated: should never be called from the child (modal) view; despite the fact that iOS helps you out and autoforwards the request to the parent.  The reason is because the second sentence is ONLY true when the modal view is the final child of a modal view stack.  If a UIViewController has a modalViewController set, then a dismiss message will result in that controller dismissing it’s child.

Every view controller that has been presented in this way (it is a child) has a property called parentViewController that is set, making it very easy for the developer to pass the dismiss message on to the proper object, even if they are not in that context at the moment.  See the example below, where versions of the right and wrong way to dismiss from a child are displayed:

@implementation ViewControllerOne
- (void)showNewView {
  ViewControllerTwo *controller = [[ViewControllerTwo alloc] init];
  [self presentModalViewController:controller animated:YES];
  [controller release];
}

- (void)dismissRight {
  //Work is done...dismiss the child
  [self dismissModalViewControllerAnimated:YES];
}
@end

@implementation ViewControllerTwo
- (void)dismissWrong {
  //Work is done...dismiss me
  [self dismissModalViewControllerAnimated:YES];
}

- (void)dismissRight {
  //Work is done...dismiss me
  [[self parentViewController] dismissModalViewControllerAnimated:YES];
}
@end

In this example, both places where dismissRight exists are proper ways of dismissing a modal, whether from the parent or child. Using the technique in dismissWrong will only get you into trouble some day.

Consider a case where a developer makes several calls to presentModalViewController:animated:, creating a view controller stack.  Every view controller in that stack has their parentViewController and modalViewController properties set…except for the top-level and bottom-level controllers, whom have the parentViewController and modalViewController properties set to nil respectively.  If a developer has the improper concept in their heads of where to send a dismiss message, messages sent to view controllers in the middle of the stack (which is allowed) would dismiss the child of the receiver, instead of the receiver itself.  This would lead to major troubles in debugging because the design concept was built on flawed logic.  JUST DON’T DO IT.

Over Retention

The other common problem arises from the fact that developers may not realize that presenting a modal view controller (through the act of setting it as the modalViewController property) causes it to be retained by the parent.  Therefore, you do not need to create properties in your parent classes to hold instances of the modal:

@interface MyViewController : UIViewController {
  ChildViewController *modalVC;
}
@end
@implementation MyViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  modalVC = [[ChildViewController alloc] init];
}

- (void)showNewView {
  [self presentModalViewController:modalVC animated:YES];
}
@end

In fact, this will keep the object from being released once dismissed, and you will be holding data from one use of the modal to the next.  If you want to make sure your modal view controller loads up fresh with each presentation, rely only on the retain message sent by the parent:

@implementation MyViewController
- (void)showNewView {
  ChildViewController *modalVC = [[ChildViewController alloc] init];
  [self presentModalViewController:modalVC animated:YES];
  [modalVC release];
}
@end

Striking the Balance: Interface Builder vs. Code

In my last post here, I touched a little on the need for a balance between building user interfaces in code and using IDE tools like Interface Builder.  Today I would like to develop the importance of that concept a little further.  People tend to become comfortable with one method or the other after they’ve been developing applications for any period of time, and they start to gravitate heavily that direction.  This can often lead to complex code or bloated NIB files in order to accomplish a task, simply for the sake of using the developer’s favorite tool.

IB vs. Code

I have cooked up a small list of advantages/disadvantages for IB and code-based UI layout:

  • Interface Builder is GREAT For
    • Quick and Precise static layout of subviews in containers
    • Easily applying parameters to views (styles, fonts, scroll parameters, etc.)
  • Code Layout is GREAT For
    • Dynamically adding/removing/moving views around in a container
    • Creating conditional view layouts based on user decisions

Building iPhone UI in a balanced fashion involves exploiting each of these strengths through some simple rules:

  1. Static element properties are easier to SET and to READ LATER in Interface Builder
    • Elements such as pickers, buttons, text fields, etc. will have parameters that do not change; such as (usually) font, backgrounds, and even frame size.
  2. Use NIB files as archives for elements that you need to lay out dynamically, but don’t want to waste the time defining in code.
    • Use the ease of IB to create, size up, and define properties for each element.
  3. Code isn’t as scary when you need only add/remove/relocate/resize
    • Many people shy away from code layout when the volume of code required looks daunting.
    • If IB does all the creation work, a few functions like addSubView, removeFromSuperView, and setFrame can get you pretty far.

Simple Example

In this example, we have a simple view controller that includes a grouped table view.  This table view needs to have a UIButton inserted at the bottom of it to perform an action associated with this view.  In addition, a picker view must be defined that will slide into place when the user needs to make a change in one of the cells.  There are two primary issues with this layout that make it difficult to do strictly in IB:

  1. UITableView is laid out with help of the delegate methods at runtime.  A button cannot just be dropped into the NIB at the table footer.
  2. The UIPickerView is a temporary visitor to this view during editing, it cannot live permanently as part of the view outlet

Some might say that these two issues require you to do the bulk of the work in code.  You could…but maybe there’s a balance that can save us some time.

With the simple rules in mind, let’s start in Interface Builder:

We want to leverage IB as much as we can for doing the things it is best at.  So we lay out the main view, which is a complex view including both our UITableView and a UIScrollView that might serve some other purpose.  Each of these is to be laid out so they fill a portion of the main screen.

Inside the NIB archive (but not the main view), we also have our picker element (a UIDatePicker) and our UIButton.  The UIButton has been wrapped in a UIView to make it easier to fit in the table’s footer.  The button we want is only 280×37 pixels, and we wrap it in a UIView that is 320×44 pixels so it fits nicely and centered once added to the table.

We also make the necessary property changes here to each element.  The UIButton is given text, and its frame’s background cleared.  The UIDatePicker is set to report only month/day/year information, and all delegates/targets/actions are connected as outlets.

All of these actions are very easy to do in IB, so we leverage its power to do them. This format makes the properties easier to set, and to read later when we have to figure out what the heck our past ‘selves were thinking!

After building the interface elements, we can do the dynamic parts in code…and the code is extremely simple. The relevant methods are shown below:

@interface BlogPostViewController : UIViewController {
UITableView *theTable;
UIDatePicker *thePicker;
UIView *buttonFooter;
}
-(IBAction)buttonAction;
@property (nonatomic,retain) IBOutlet UITableView *theTable;
@property (nonatomic,retain) IBOutlet UIDatePicker *thePicker;
@property (nonatomic,retain) IBOutlet UIView *buttonFooter;
@end

@implementation BlogPostViewController

- (void)viewDidLoad {
    //Using code to link the IB button into the table view
    [theTable setTableFooterView:buttonFooter];
}

- (IBAction)buttonAction {
    //Using code to dismiss the picker as an editor
    [thePicker removeFromSuperview];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    //Using code to display the picker as an editor
    [self.view addSubview:thePicker];
    CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
    CGSize pickerSize = [thePicker sizeThatFits:CGSizeZero];
    CGRect destinationRect = CGRectMake(0.0, screenRect.origin.y + screenRect.size.height - pickerSize.height,
                pickerSize.width, pickerSize.height);
    [thePicker setFrame:destinationRect];
}

@end

Now we only needed one line of code to attach the UIButton, which is used to dismiss our picker, to the table footer. The removal action of the picker is also a single line of code. The example brings up the picker when a user selects any table cell. This code is also very simple, with the most complex part being the calculation of the y-coordinate to use for placing the picker.

This example is not production-ready.  In most cases you would add the subview (like the picker) off-screen (make origin.y larger than the screen height), and then animate a frame change bringing it into view.  But the basics are here to show how simple the code can be when IB handles all the setup work.  Conversely, it would have been extremely difficult to try and lay out the button and picker to be dynamic using only IB as our UI tool.

UIScrollView has a Secret

Sometimes, it’s not always clear in iPhone development when one should create their interface elements using Apple’s Interface Builder (IB) application, or directly in application code.  Oftentimes, with more complex view issues, the answer tends to be a combination of both.  When doing this, however, it is not uncommon for little traps to come out of hiding that can be hard to trace down.

One such instance lives within the UIScrollView element.  The developer may choose to lay out the element in its superview using IB to ensure proper placement and sizing relative to the rest of the view.  However, because of the dynamic nature of content placed within UIScrollView, the population and sizing of the content view may take place in code.  When using IB to lay out a UIScrollView, the Attributes Inspector will give the developer options similar to what is shown on the right.

The Scrollers Are Hiding

I want to draw your attention to the checkboxes named “Horizontal” and “Vertical” by Scrollers heading.  As many of you may know, these options turn the scroll bars that appear on the sides of the view during a scroll operation ON and OFF.  By default, these boxes are checked and the scroll bars are active.

Now for the secret: When those scrollers are active, the unarchived version of your object will have two extra UIView objects in your subviews array…one for each scroller bar.  If you were to look at the object in the Xcode Debugger, you would see that the type of these objects is actually _UIStretchableImage (which is a private UIView subclass).

This means that, if you plan to iterate over the subviews array at any time, your code may throw an exception on unrecognized selector or some other method because it is accessing objects in that array you may not have known existed (and don’t understand your custom message).

Secret #2: _UIStretchableImage is also a subclass of UIImageView, or at least to the point that it will return YES from a call to [view isKindOfClass:[UIImageView class]].  Therefore, if you like to use UIScrollView for images and think you can outsmart this by checking the type of each subview object, you’ll have to use another method.

This can also have consequence if you plan to loop through the subviews array to clear the content with [view removeFromSuperview], so be aware of that as well. You may just lose your scroll bars without realizing why!

Editorial: Your Reviews May Be Hurting You

Normally, I target developers in my posts, but today I had a special message that I wanted to send out to the user community.  I’ve noticed a trend over the past year that troubles me some about the way users are using their reviewing power in places like the App Store or the Android Market.

Users, the power you’ve been given to review mobile applications carries more weight than I think many of you give it credit for.

The consequences of an application review should not be taken lightly.  Believe it or not, other users do look at an app’s comments (or at least the top five at the time) and it’s current rating.  This can be a good thing, but it behooves me to point out that there are certain things that do not belong in reviews as they can prematurely cripple and application’s, or its developer’s, success.  Flagrant user of 1 star ratings for certain reasons will end up hurting the user community if used improperly, because many of the developers will choose not to develop more apps or make updates to those they’ve already published.

Here is a list of things that I believe low ratings and review comments SHOULD be used for:

  • Lack of developer feedback
    • I 100% agree that if you contact a developer with a question on an application, and get no response within a few days, you have the right to rate low.  Active applications need developer support.
  • Poor application quality
    • Try to distinguish poor user experience from a missing feature.  Just because an application doesn’t have a feature you think would be cool, doesn’t mean it is somehow broken.

Which brings me to things low ratings SHOULD NOT be used for:

  • Feature requests
  • Bug reports

A good developer enjoys hearing feedback about their application, and ways that they can improve the user experience in future releases.  This is why application markets provide developer contact information, so you may contact them directly with this type of feedback.  The salient point here is to give the developer(s) an opportunity to support you first.  Your helping them by letting them help you.  Often, a missing feature isn’t missing…just hidden.  By contacting the developer, you’ve learned where the feature is, and they’ve learned it needs to be more obvious where to find it next time.

The same goes for bugs.  App development is a small-scale business oftentimes, and developers can’t be as thorough with software testing as we all would like.  So, sometimes the user community ends up becoming beta testers on the first 1-2 releases of an application.  Again, direct contact will get these issues solved more quickly.  You will most likely be waiting longer if you post a bad review and expect that the developer saw it.

So, I guess the bottom line here is open dialogues with the app developers and, in the long run, you’ll be glad you did.  If the developer ignores your requests, then use that veto as it was intended.  Developers who ignore their users don’t have a place in this community anyway, in my humble opinion.

App Released: Ohm’s Best

Ohm's Best

Today Wireless Designs released Ohm’s Best for the iPhone, available for download on the App Store.

Ohm’s Best is an electronics calculator application that allows electronics technicians and electrical engineers to do circuit calculations using real component values that one can actually find and purchase.  This functionality puts reduced design time and frustration right into your pocket.

Check out the full press release at iPhoneAppReview.com

If you download the app, please send us feedback via email or twitter.  We love to hear how we can improve things to help you better!

What’s awakeFromNib for?

Sometimes traversing through the life-cycle callbacks of view loading on the iPhone still gives me a headache.  Especially when using Interface Builder (IB) as part of the UI development, finding the right method to override in order to get your custom drawing/init/etc. done can be more difficult than it may seem.  Recently, I was lost again in the quagmire of methods to choose from when building a custom UIView subclass that provided some basic look-and-feel customization over the standard view structure  The answer that was revealed to me is today’s tip.

awakeFromNib

The commonly recommended place to do custom initialization for custom views is in the initWithFrame or initWithCoder methods.  When you are defining parts of your UI in IB, initWithCoder is the one of these that is called by the nib-loading code.  However, it is usually the case that any work done with members declared as IBOutlet are still nil at this point, so your custom changes will fall on deaf ears.  This drives many developers to put custom initialization code in the viewDidLoad method of the view controller…because it works.  The problem here is a conceptual one.  You are no longer encapsulating all of the custom functionality for your view in the view class, some of the required custom code is leaking out into the controller.  You are now relying on code in the custom view’s container to provide some of the needed functionality to properly initialize the view, which makes the code brittle.

Enter awakeFromNib; a UIKit addition to NSObject that receives a message from the nib-loading code after all the outlets and actions have been connected for all objects inside the nib file.  Apple states that “When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.”  This means you can now comfortably make some changes to properties that would have otherwise been nil during the init phase.  This allows you to put that custom code back into the view subclass, properly encapsulating the functionality.

Don’t Get Lost! Tag your Comments!

Project Management, like version control, is something every developer should always be doing at some level in their work…period.  Regardless of the size and scope of a project, basic task management keeps things moving in the right direction.  However, I’m not saying that this should require some elaborate process either.  Oftentimes, a complex process can drive efficiency into the floor.  There is a common standard among major Integrated Development Environments (IDEs) that allows a developer to do a little bit of their own “in situ” project management using code comments…and I believe that this feature is drastically under-utilized.

These comment tags are recognized by IDEs and can be used to quickly and effectively build simple To-Do lists to help you complete all your objectives, or even just place markers in the source so you remember where to go back to.  Because of the scope of my recent work, and of this blog, my examples will focus on Xcode and Eclipse.  However, the general principle applies to many others out there.

Creating Comment Tags

There are two common keywords that work across IDEs: TODO and FIXME.  By placing comments like the following in your code, your on your way to managing what you need to do next, and where you need to do it:

// TODO: Add a method to handle incoming floats
// FIXME: The app crashes here when releasing the object

Placing these at the location where they are relevant will save you time and headache in situations like these:

  • Picking up where you left off the day before
  • Marking a location in a file when you have to move to another while tracing
  • Fleshing out stubs (start with a list of TODO comment before you write any code)

While this is a nice and simple procedure to follow, its the IDEs reaction to these that really makes them useful…

Xcode

Xcode recognizes the following tag styles in comments:

// TODO:
// FIXME:
// ???:
// !!!:

Note the colons on the primary tags, because Xcode needs them.  Notice also that there are two more generic tags that can be used to further subdivide your task listings (??? and !!!).  With these tags in your code, Xcode helps you out by placing markers in the file listing (where you also find your #pragma mark statements).

Each tag is organized underneath the method where it is located.  You may also choose to group your tags at the beginning of the file, as was done in the example above.  This cleans up the listing and puts all the tags in one place, but you don’t gain the ability to click and be transported to the relevant location.  It’s up to you!

Eclipse

Eclipse recognizes the following tag styles in comments:

// TODO
// FIXME
// XXX

Note that Eclipse provides one more tag to further assist you in subdividing your tasks (XXX, which must be capitalized).  With these tags placed in comments, Eclipse does three things for you:

  • Include a blue marker on the scroll bar in the source view (in the same location as yellow markers for warnings and red markers for errors)
  • Include a clipboard task marker on the left bar in the source view
  • Provide a Tasks View where you can view all active tags in all the files of your project at one glance.

The scroll bar marker feature is what makes using TODO or XXX tags as placeholders useful.  You can tag a location, move down to a method you need to finish, and then pop back to where your tag is.

The Tasks View may not be visible by default in Eclipse, but can be brought up from the Window -> Show View -> Other… menu (there is an option called Tasks).  Here you will be presented with a table that points out each tag and its location.  FIXME tags are marked with the exclamation point by default as well.

For the same reasons that single developers should always use version control, basic management of your tasks is crucial to happy and sane development.  In my opinion, this is a great start and it doesn’t get any simpler than this.

iPhone Tip: Info Button Woes

Today’s tip is a simple solution to a common problem.  The fix for this problem is all over the internet, but none of the places I visited seemed to give the whole story, they only revealed a piece of the puzzle (sorry for the cliché).  All of us who use the iPhone with any frequency have seen the info button used in onr place or another.  This cute little circle with a lower-case “i” inside is a popular widget used by Apple to denote a way to gain access to details like application settings.

When developers start using this widget in their own code, often two very distinct symptoms pop up instantaneously as soon as they get their app onto a real device:

  1. Often I have to tap the button 3 or more times before it detects the event!
  2. Sometimes (usually when debugging) I tap the button and it recognizes the event seconds later!

This can be a frustrating problem to troubleshoot, especially for a new developer, and is exacerbated by the actual root of the problem…the button is just too darn small!

The Solution

So what do we do about this?  Well, many of us would intuitively try to open up Interface Builder and increase the widget size.  However, Apple has fixed the button’s frame to 18×19 pixels and it cannot be changed through IB.  So for those of us who like to do as much UI layout in IB as possible, we have to roll up our sleeves and write a little code.  Don’t be scared, there isn’t much to it:

The Code

As I mentioned, IB grays out the frame of the Info Button, but it isn’t really a fixed value; you can declare a new frame and apply it to the button in code.  First, choose the amount by which you want to increase the button (I usually use 50 pixels), and let’s call that value “G”.  The following code will shift and grow your frame around the info button.

CGRect newInfoButtonRect = CGRectMake(infoButton.frame.origin.x-(G/2),
          infoButton.frame.origin.y-(G/2),
          infoButton.frame.size.width+G,
          infoButton.frame.size.height+G);
[infoButton setFrame:newInfoButtonRect];

Code adapted from iPhone SDK Examples.

The Location

So where does this code need to be?  In the UIViewController that handles the button.  I’ve had varying degrees of success putting this code in different methods, but putting it into viewDidLoad: seems to yield the best results.  Don’t forget that the info button must be defined as a property in the UIViewController so we can work with it.  The example below assumes you define your layouts in IB, so the button is also an IBOutlet:

UIViewControllerSubclass.h

@interface ... {
    UIButton *infoButton
}
...
@property (nontatomic,retain) IBOutlet UIButton *infoButton;
@end

UIViewControllerSubclass.m

...
- (void)viewDidLoad {
    CGRect newInfoButtonRect = CGRectMake(infoButton.frame.origin.x-25, infoButton.frame.origin.y-25,
          infoButton.frame.size.width+50, infoButton.frame.size.height+50);
    [infoButton setFrame:newInfoButtonRect];
    [super viewDidLoad];
}
...

Also, don’t forget to connect the newly created outlet to the Info Button you have defined in IB. With your button’s frame freshly enlarged, give the app another try and see how much easier it is to properly trigger the info button with a real finger!

Editorial: Why Android Deserves Your Attention

I’ve read an increasing number of articles on the web recently from people who fervently believe that the Android platform is dead before it ever really got started. The common mantra going along with this is that Android is late to the party, and they didn’t bring anything new with them. First of all, I’m not sure how anyone getting into the game at this stage could be considered late, as the smartphone market is still quite infantile and rapidly developing…but I digress. Personally, I am very surprised by this perception, and have to wonder why the (mainly) iPhone community is so quick to attack?

I am a daily user of both the iPhone and Android platforms, and develop applications on both platforms as well. There are things about both that I love, and there are things about both that I hate; both as a user and developer.  I’m not the expert, and this is not an exhaustive comparison, but here are reasons that I believe Android deserves your attention (“you” being the developer) and why it is not dead…even if it doesn’t doesn’t immediately become king.

For context, as I’m writing this the latest software versions in the market are Android 2.1 and iPhone 3.1.2

The User Experience

There are some feature that Android provides to the user that the iPhone will need to incorporate eventually, in my opinion.  And I’m discussing them from a user perspective (not technical discussions of memory management, code efficiency, etc.)

  • Customizing Home Screen (Widgets)
    • The mobile user has severe A.D.D.; myself included. The faster the relevant content arrives to me, the less annoyed I am at how long I had to wait.  Checking the basics, like the Top 10 on my To-Do list or my next upcoming appointment, should not require me to run each application individually.  With Android, that data can live on my home screen in the form of widgets, and I can view it all right on the desktop (background services help a lot with this also, but we’ll get there).  And the data is REAL, it is not an image file stored and plastered as wallpaper.
  • Activity Stacking
    • My brain (and my life) works a LOT like a stack.  Often, what I am working on currently has something pushed on top of it that requires attention.  When I am done with that higher priority item, I need to step right back to doing what I was beforehand.  The Android concept of working follows this paradigm very well.  If I’m working in an application and need to send a quick email, I can bring email up on top of my current activity and do what I need to do.  After I am done with the email, I can go back to my previous activity and it is uninterrupted.  The same holds true if I get interrupted by a text message or other priority notification, I can load this activity ON TOP of what I was doing.  The tag line here is that I don’t have to close my old thoughts to start a new thought.

The Developer Experience

From the developer perspective, Android offers some neat opportunities as well.

  • Background Processing (Services)
    • Last year, when Apple announced that Push technology would be available to the iPhone, there was an uproar of excitement.  Suddenly, applications could grab the user’s attention without the need for the application to be running.  Push technology definitely has it’s place, but I do not believe that it can ever truly replace a background service in all instances.  Sometimes, developing a complete back-end server application and connecting with the Apple service is just too much overhead to put in to a project that just needs a method of notifying the user or doing simple work in the background.  Mobile devices may be resource constrained compared to the desktop platform, but I shouldn’t be afraid to run a few concurrent processes locally.  Shoot, I can do that on an 8-bit microcontroller.
  • System Modularity (Intents)
    • Intents embody the concept of inter-process communication and make it easy to modularize a system.  This architecture brings up a neat realization: once your app is using these to talk to itself, it’s a very small leap before apps start talking to each other.  This can be especially useful if you embrace the design philosophy that mobile apps should not have too many jobs, and that they should do 1-2 tasks efficiently.  Using an architecture based around Intents, complex tasks are now possible, while still holding true to the simplicity of each individual application.  This also provides great flexibility into way of hooking up with the core applications on the device (like mail and contacts) as just another module to your system.

I love my iPhone, and I love developing iPhone applications.  There are a lot of things on both the user and developer front that I prefer about Apple and the iPhone SDK.  I’ve chosen not to delve into them because so many people already have.  Any of the articles that I mentioned in the beginning spend a great deal of time touting the iPhone’s better features, so I’m just going to acknowledge (and agree) that they exist.  While these features alone may not skyrocket Google and cripple Apple, I believe that they are definitely enough to point out that Android has brought some new tricks to the party, and you probably ought to take notice.  I believe that they ARE enough to keep Apple from crippling Google straight out of the gate.