iOS Pain Points: $99 per year developer program

In order to distribute your work on the app store, or test your work on your device, you need to sign up for the iOS developer program at a cost of $99 per year.

What purpose does this fee serve, aside from turning away potential developers?

It’s certainly not making Apple rich. According to Apple, there are over 500,000 apps on the app store. If we make the tenuous assumption that there’s a 1 to 1 ratio of apps to app developers, we can guess that there are around 500,000 registered iOS developers, who altogether make Apple a tidy sum of $49.5 million dollars per year. Sounds great, right? Well, not when you consider that Apple took in $28 billion┬áin revenue in the last quarter alone. That 49.5 million dollars in annual developer program fees is approximately 0.017 % of Apple’s quarterly revenue. Less than a drop in the bucket.

No, the real reason, as I see it, is to intentionally raise the bar to attract only the developers who are serious about the platform. Were there no annual fee, the app store would likely be (even more) deluged with lower quality apps, and the approvals team would be even more swamped than they already are. This is certainly a valid point, but it hurts small developers, as even the simplest apps now have to sell approximately 142 copies per year just to cover the developer program fees (and that’s not even considering the other fees associated with iOS development). As a newcomer to iOS development, this is a somewhat scary number.

Since the motivation for the annual fee is quality, not direct financial gain, I have an idea to ease this pain: refund some or all of the fee for each app that is successfully submitted to the App store. By doing this, Apple would still create its desired barrier to entry, but it would be less of a burden on small-time developers. And as the money would not be refunded until an app successfully passed the submission process, developers would have just as much incentive – if not more – to release high-quality apps.

Of course, none of this matters, because Apple would never do such a thing. But I can dream.

iOS Cool Stuff: Storyboards

Storyboards are one of the coolest features of Xcode and iOS development. New to Xcode 4.2, they not only give you a visual overview of all the screens in your application, but they show you the transitions – or segues – between the screens.

This is a few steps above and beyond the likes of what Visual Studio can do. Instead of seeing a single control or a single window at a time, you can see all of them, plus the way they relate to each other.

Some of the features of storyboards are not particularly discoverable, though, such as the Ctrl-clicking and dragging to create a segue (or an outlet, but I believe that’s just part of Interface Builder that’s been there for a while, not a feature specific to storyboards). There are also some fairly unintuitive behaviors with regards to zooming and selecting. It appears that there are only four zoom levels – you can’t zoom in or zoom out arbitrarily. And selection works differently at the different zoom levels. For example, if you aren’t zoomed in all the way, you can’t select individual controls; you can only select entire views. But if you click on a control in the document outline, you are suddenly zoomed in to it. Not deal breakers, of course; just things that might initially surprise you.

Minor quibbles aside, storyboards are a terrific step forward in the realm of visual designers, and one that I would love to see in Visual Studio.

By the way, if you’re looking for a great storyboard tutorial, check out Ray Wenderlich’s Beginning Storyboards Tutorial.

iOS Pain Points: Multiselect of UITableViewCell children in Interface Builder

This is a quick one.

Multiselect in a UI designer is a pretty standard operation. If I want to change a property on a number of controls at once, I should be able to simply ctrl-click them (or command-click, or option-click, and so on) to select them all, and change the property.

Unfortunately Interface Builder doesn’t seem to support multiple selection on controls in different UITableViewCells. Attempting to do so always results in the first control being deselected.

However, there is a workaround, which is why this entry is really half ‘iOS Pain Points’, and half ‘iOS Quick Tips’. It turns out you can multiselect across table cels by command-clicking in the Document Outline window on the left.

Not entirely intuitive, but it does the trick!

iOS Quick Tip: Setting the default view controller on a storyboard

Figuring out how to set the default view controller on a storyboard is surprisingly unintuitive, especially as someone new to iOS development. It seemed logical to me that it would be some sort of setting on the storyboard itself. However, it’s actually the exact opposite – it’s a setting on the view controller.

This is somewhat bizzare as it means setting a property on one view controller can affect other view controllers, but nevertheless, it’s quite simple. Here’s what you need to do:

  • Open your storyboard
  • Click on the view controller corresponding to the view that you want to be the default view
  • Open the Attributes Inspector
  • Check the Is Initial View Controller check box in the View Controller section

Voila! Your view controller is now the default view controller for this storyboard.

iOS Quick Tip: Filtering a UITableView with a search bar

Step 1: Add a UISearchBar to your UITableView and create an outlet for it.

Step 2: Add properties for the array of all the table data, and the array of filtered table data.

@property (strong, nonatomic) NSMutableArray* allTableData;
@property (strong, nonatomic) NSMutableArray* filteredTableData;

Step 3: Assign your search bar’s delegate to your controller class.

-(void)viewDidLoad
{
    // ...Do initialization stuff here...

    searchBar.delegate = (id)self;
}

Step 4: Implement the searchBar:textDidChange: method from the UISearchBarDelegate protocol. This will let you filter your list as you type. If you want to filter when the search button is clicked, use the searchBarSearchButtonClicked: method instead.

In this example, we are searching through a list of foods with names and descriptions to see if the match the search text. If they do, we add them to our NSMutableArray containing our filtered foods. We also set a flag that indicates whether or not we are currently filtering the list.

-(void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)text
{
    if(text.length == 0)
    {
        isFiltered = FALSE;
    }
    else
    {
        isFiltered = true;
        filteredTableData = [[NSMutableArray alloc] init];

        for (Food* food in allTableData)
        {
            NSRange nameRange = [food.name rangeOfString:text options:NSCaseInsensitiveSearch];
            NSRange descriptionRange = [food.description rangeOfString:text options:NSCaseInsensitiveSearch];
            if(nameRange.location != NSNotFound || descriptionRange.location != NSNotFound)
            {
                [filteredTableData addObject:food];
            }
        }
    }

    [self.tableView reloadData];
}

Step 5: Modify our other UITableViewController methods to make them aware of the isFiltering flag, and to use the correct list depending on whether or not we are filtering.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int rowCount;
    if(self.isFiltered)
        rowCount = filteredTableData.count;
    else
        rowCount = allTableData.count;

    return rowCount;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];

    Food* food;
    if(isFiltered)
        food = [filteredTableData objectAtIndex:indexPath.row];
    else
        food = [allTableData objectAtIndex:indexPath.row];

    // ... Set up the cell here...;

    return cell;
}

Voila! You now have a UITableView that can be filtered using a UISearchBar.

Download the UITableView Filtering Demo Project (updated July 8, 2012 to show row selection and disclosure indicator handling).

iOS Pain Points: Constants and enums are not discoverable

Let’s say I want to use a UIImagePickerController to take some photos.

UIImagePickerController* controller = [[UIImagePickerController alloc] init];
controller.sourceType = 

Ok, I’ve finished typing the = sign on the second line. Now I would like to type the actual source type value that I am assigning. Surely Xcode can help me out with this? I mean, intellisense/content assist/code completion is a pretty basic IDE feature. But Xcode does nothing by default. Ok, fine. I’ll hit Esc to manually invoke autocompletion.

Xcode, in all its wisdom, gives me a completely useless list of dozens or hundreds of irrelevant entries.

Fine, I happen to know that enums generally start with the name of the control. I will manually type in ‘uiimagepickercontrollers’, to finally get a list of the available UIImagePickerControllerSourceTypes. All in all, it’s a horrible user experience.

Now let’s move on to something even worse. It’s time to configure my controller’s media types:

controller.mediaTypes = wtf?

Ok, so mediaTypes is an array of, well, stuff, since Objective-C arrays aren’t strongly typed, as we saw in the previous ‘iOS Pain Points’ entry. So I have no information on how to use this API, and code completion is telling me nothing. No problem, I’ll just look at the Quick Help window in Xcode.

Great, it’s ‘An array’. Thanks, Xcode. Not to worry, though. I’m familiar with the standard mentioned above, where types generally start with the name of their control, so I’ll just look for UIImagePickerControllerMedi… ok, scratch that. Turns out, I actually need to use a constant such as kUTTypeImage, which is declared in a different file. Or to put it another way, it’s literally impossible to use the UIImagePickerController without looking at the documentation to figure out what the allowed values are for what fields. It’s a case study in poor, non-discoverable API design and inadequate IDE integration.

For reference, here’s what using an enum in C# / Visual Studio looks like:

Apple could learn a thing or two from Microsoft here.