A couple of compact code idioms

Since we write code once but then read it many times there is an obvious desire to write less code so we have to read less code later. One of the ‘local optimizations’ I personally do is to compress if statements so they are easier to read. But first there is a thing that you should know: never skip curly braces! Formally if you have a single statement in if clause you can skip them but it could easily lead to logical errors, especially if you don't care to format code properly.

The first idiom is a read–only property that returns a mutable collection (or any other object actually). I typically follow this pattern in model objects. You define a read–only property, private ivar and getter method which initializes ivar if necessary and returns it. Turns out there is a nice way to write this method in a single line.

The second idiom is a parameter check for nil value: if you have to put it into collection you probably would like to use [NSNull null] to avoid crash. Normally you would write if statement but there is a shorter way to write it using just an expression. The first part is nil check and the second part is assignment which evaluates only if the first part is true.

Below is a simple class that demonstrates this; hope you will find it useful.

@interface Test ()

@property(readonly) NSMutableDictionary *dict;

@end


@implementation Test {
@private
  NSMutableDictionary *_dict;
}

- (NSMutableDictionary *)dict {
  return _dict ? _dict : (_dict = [[NSMutableDictionary alloc] init]);
}

- (void)setBoogie:(id)boogie forKey:(NSString *)key {
  !boogie && (boogie = [NSNull null]);
  !key && (key = @"default");
  [self.dict setObject:boogie forKey:key];
}

@end

Badge for UITableView cells using UIButton

Most people think of UIButton only as of control that could be used to create buttons. But in its API you will see that it is possible to provide a background image, label and content insets, which opens many other interesting use cases for the UIButton. There are actually other useful properties but these three enable UIButton to be used to construct badge labels. Like these for example:

Badge Button Demo

So how these cells are made? First, we create an image for the badge which will be stretched to contain the number:

Button Badge

Then we create a UIButton and set its background image to be the stretchable badge image. And actually that’s all. Here is the method that creates cells for the image above:

- (UITableViewCell *)makeBadgeCell:(UITableView *)tableView
                         withCount:(NSUInteger)count
{
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BadgeCell"];
  UIButton *badgeButton;
  if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                  reuseIdentifier:@"BadgeCell"];
    UIImage *bgImage = [UIImage imageNamed:@"cell-bg.png"];
    UIImageView *bgView = [[UIImageView alloc] initWithImage:bgImage];
    bgView.contentMode = UIViewContentModeScaleToFill;
    cell.backgroundView = bgView;
    UIImage *hlImage = [UIImage imageNamed:@"cell-bg-hl.png"];
    UIImageView *hlView = [[UIImageView alloc] initWithImage:hlImage];
    hlView.contentMode = UIViewContentModeScaleToFill;
    cell.selectedBackgroundView = hlView;
    
    cell.textLabel.textColor = [UIColor whiteColor];
    cell.textLabel.backgroundColor = [UIColor clearColor];
    cell.textLabel.opaque = NO;
    cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
    cell.textLabel.text = @"Text";
    
    badgeButton = [UIButton buttonWithType:UIButtonTypeCustom];
    badgeButton.tag = kBadgeButtonTag;
    UIImage *badgeImage = [[UIImage imageNamed:@"button-badge.png"]
        stretchableImageWithLeftCapWidth:15
                            topCapHeight:10];
    [badgeButton setBackgroundImage:badgeImage forState:UIControlStateNormal];
    badgeButton.adjustsImageWhenHighlighted = NO;
    badgeButton.contentEdgeInsets = UIEdgeInsetsMake(1, 8, 1, 8);
    [badgeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    badgeButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
    badgeButton.titleLabel.textAlignment = UITextAlignmentCenter;
    [cell.contentView addSubview:badgeButton];
  } else {
    badgeButton = (UIButton *)[cell.contentView viewWithTag:kBadgeButtonTag];
  }
  [badgeButton setTitle:[NSString stringWithFormat:@"%d", count]
               forState:UIControlStateNormal];
  [badgeButton sizeToFit];
  CGRect badgeRect = badgeButton.frame;
  badgeRect.origin.x = 300 - badgeRect.size.width;
  badgeRect.origin.y = (44 - badgeRect.size.height) / 2;
  badgeButton.frame = badgeRect;
  return cell;
}

The sample project is available on github.

Menu system with tables and navigation controllers

I was recently set to write a hierarchical menu system for iOS app. The idea was to quickly add necessary functionality like user session handling and simple help system without designing a lot of dedicated pages. Yes, some applications feature witty login and registration pages but when it’s not the most significant part of the application maybe you could start with something more conventional.

So the idea was to use UITableView in grouped mode to show menu items and UINavigationController to move between pages back and forth. The expected result should look like this:

Menu System Home

Typical approach would be to use UITableViewController for each menu page, but that has two major drawbacks:

  1. You have to write some boilerplate code for each page
  2. It’s a pain to enforce consistency among menu items

The second point means that if you want to change a look of cells you have to do it in all page controller classes. And we all know that it is better to have one place for such changes. The solution then is to think what is common for all pages and try to factor out as much as possible.

The first observation is that view controller for all menu pages could be the same and they all differ by implementation of table’s data source and delegate. So we introduce a MenuProvider class which extends NSObject and implements UITableViewDataSource and UITableViewDelegate protocols. For every page we will create an instance of common MenuViewController and parametrize it with a particular MenuProvider instance.

Menu System Register

Now we notice that in our menu we have certain cell categories:

  1. Navigation cell: it has chevron at the right side, main text and maybe detail text. On touch it opens some other menu page.
  2. Text entry cell: used to ask user for some text like email and password.
  3. Action cell: works as a button.

Since we have to create instances of these cells in all our MenuProviders it makes sense to add factory methods to the base MenuProvider class to do so. Now we have a single place where we could change how all menu cells of a certain type look like.

typedef void (^MenuNavigator)(NSString *destination);

@interface MenuProvider : NSObject
<UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>

@property(nonatomic, readonly) NSString *title;
@property(nonatomic, strong) MenuNavigator navigator;

- (UITableViewCell *)tableView:(UITableView *)tableView
        navigationCellWithText:(NSString *)text
                    detailText:(NSString *)detailText
                  destination:(NSString *)destination;

- (UITableViewCell *)tableView:(UITableView *)tableView
            actionCellWithText:(NSString *)text
                 textAlignment:(UITextAlignment)textAlignment
                selectionStyle:(UITableViewCellSelectionStyle)selectionStyle;

- (BAEditableCell *)tableView:(UITableView *)tableView
        textEntryCellWithText:(NSString *)text;

@end

Yet another thing that we could factor out is navigation. We have to implement tableView:didSelectRowAtIndexPath: for each provider and when a navigation cell is tapped create MenuViewController, specific MenuProvider and push them to the navigation controller. The same sequence for all such cells—obvious target for refactoring. My solution is to parametrize each navigation cell with a certain 'destination'—identifier of a menu page that should be opened. Then we could add a generic piece of code to handle navigation requests.

Menu System Help

One interesting addition is the help pages. App bundles several static html files each covering a particular help topic. When you navigate to a help topic menu creates instance of MenuTextViewController which loads an html file into the UIWebView. And in order to specify which file to load we use the same 'destination' property. Now when the navigation cell wants to load the next page it first tries to create a MenuProvider associated with its 'destination' property. If it can't create MenuProvider it tries to load html file with the name specified by 'destination' property.

Here is the method that makes a menu page accordingly to the discussed principles:

+ (MenuViewController *)makeMenuControllerForDestination:(NSString *)destination {
  MenuProvider *provider = [self makeProviderForDestination:destination];
  if (!provider) {
    return nil;
  }
  MenuViewController *menuController = [[MenuViewController alloc] init];
  menuController.contentSizeForViewInPopover = kContentSize;
  menuController.provider = provider;
  __unsafe_unretained MenuViewController *weakMenuController = menuController;
  provider.navigator = ^(NSString *destination) {
    if ([@"back" isEqualToString:destination]) {
      [weakMenuController.navigationController popViewControllerAnimated:YES];
      return;
    }
    MenuViewController *menuController =
        [self makeMenuControllerForDestination:destination];
    if (menuController) {
      [weakMenuController.navigationController pushViewController:menuController
                                                         animated:YES];
    } else {
      MenuTextViewController *textController =
          [self makeTextControllerForFile:destination];
      if (textController) {
        [weakMenuController.navigationController
            pushViewController:textController animated:YES];
      }
    }
  };
  return menuController;
}

The source code is available on github. I encourage you to look at MenuHomeProvider, MenuLoginProvider, MenuRegistrationProvider and MenuHelpProvider classes and see for yourself how slim and clear they are. At the same time all power of table's data source and delegate callbacks are available to you to customizes the pages as needed.

Technical interviews

Not so long ago I’ve attended a technical interview and on the way back home thought about the process. Inevitably you imagine yourself on the other side and start thinking what would you ask to understand a person and figure out what he or she is capable of. In most cases you are asked to solve a simple problem like reversing a string. This shows that you know a programming language and generally is a sane person but it does not tell that much about how good an engineer you are. So here is what I would do:

  1. Review code written by the person in real-life projects.

    • Run static analyzer over the code; discuss the results. If there are warnings then ask to explain what do they mean and how to fix them. If there are no warnings then chances are that you have found a really good developer )))
    • See if code is formatted and well-structured. I strongly believe that proper formatting and structuring is strongly correlated with overall quality of the code and documentation developer produces.
    • Ask to explain certain design decisions. This is about tactical thinking and understanding of patterns and idioms.
    • Discuss performance of the code. Once again, a lot to find out from characteristics of data structures to language implementation details.
  2. Find bug in other’s code.

    The idea is to take some rather large application (sure github will help) and introduce several bugs in it. Describe the effects of these bugs and ask the person to find them. It’s a typical situation you have in real life and I just don’t understand why this task is not given at interviews.

  3. Rabbit hole.

    Open a browser and type in some url. Wait until page loads. Ask the person what happens inside the computer and to go as deep as he can: how browser UI works, which controls are used, how HTTP requests are formed, how they are passed to the backend, processed there and so on. Feel free to go as deep as how bytes are packed and transmitted and as broad as how internet protocols and services cooperate to deliver the traffic.

    I guess if you have someone who is really interested in programming and not just learned Java or whatever to earn easy money he or she could spend hours answering this question.

By changing string’s case you can change its length

What will this code snippet print?

NSString *s = @"süß";
NSLog(@"%d: %@", [s length], s);
s = [s uppercaseString];
NSLog(@"%d: %@", [s length], s);

That's the thing that you should be aware of: converting string to uppercase or lowercase may change its length. It turns out that there is no capital ß letter and thus it is expanded into SS. So the printout is this:

3: süß
4: SÜSS

Why it is important? You could assume that the length will not change and cache the length of a string or ranges of some substrings. If you use these values on converted string you can get wrong results or even crash the app. The bug is so subtle that you will have hard time figuring out what's going wrong.

So just remember this thing when working with strings: by changing string's case you can change its length.

Grouped page control

Actually I have written three page controls so far (who knew that I would need all of them). So here they are:

  • BAPageControl: features several fixed styles and allows to specify colors for active and inactive dots
  • BACustomPageControl: you can specify images for active and inactive dots
  • BAGroupedPageControl: when you have too many pages to fit on screen you can show them in groups

And in this post I will talk about this last control—BAGroupedPageControl.

The problem that I faced with one of my apps is that I had too many pages for the page control to show. The first solution was to add "continuous" styles to the BAPageControl and they work very well indeed. The idea is to show individual dots when the number of pages is small enough for dots to fit in screen bounds. But when they don’t fit show something like progress indicator so you have a sense where you are in the list of pages. The downside of this approach is that the control changes visually too much, which could be confusing.

My next solution was to introduce grouping so that pages are packed in groups and only one of the groups is visible at any given moment (the group which contains the current page). To indicate that there are more pages available I draw tiny arrows at the sides of the control.

Grouped Page Control

Speaking of API it is the same as in BAPageControl minus "continuous" styles. There is one additional property to specify the number of pages per group.

I also had plans to sell this control on sites which specialize on selling reusable components. For several months it was available at binpress.com but they all gone without a single purchase.

Grouped Page Control Sales

So now this control is a part of the BaseAppKit framework, enjoy!