Another Brick in the Wall

Another Brick in the Wall

We are proud in i3factory to introduce a new term related to the way we make our apps: this is the “iphone brick”. Unfortunately this term is mainly used (try to make a search on google) to identify those bricked iPhone, that is devices that stop to work properly.
In our case we think at the brick as a major block that can be easily integrated in each application thus providing standardization and ease of use and testing.

So what is a “brick”? it’s a basic component that provides a full functionality with minimum programming level customization and some UI degree of flexibility. We already used bricks in our music applications, we have one for detecting notes (listener), we have one for playing basic sounds, we have another one to present simple e-books.

The theory behind bricks can be easily proven by one of the basic design patterns in iPhone CocoaTouch programming: the MVC – Model View Controller.

Summarizing, this pattern separates the role of a View, that is the part of code dedicated to user interface, to data presentation and user interaction, of the Model, that is the part of code hidden to the user and that represents the data model behind the app, and finally the Controller, that is the glue between the View and the Model and which is the part of code that knows the application logic and orchestrates the View and Model interactions.
Of course you’re not strictly required to keep these entities well separated in your code, especially in the iPhone where the UIViewController class is basically a Controller containing one or more views.

Now a standard iPhone app is based on a sequence of pages that are displayed to the user according to the application logic. This may happen in several ways, that is by navigating into a model hierarchy (typical left to right view panning), or flipping views, or showing modal views (typically bottom to top view panning) or finally switching between them using a tab bar.
Each one of these pages knows the portion of application logic that it represents: e.g. a page whose purpose is to show the user a database query knows where to fatch data from or, at least, is getting this data from the view that’s calling it; and the same page knows how to react once the user select one of the database entries it’s showing.
Typically a page is both a controller, because it contains a slice of the application flow, it’s obviously a view, because it shows something and interact with the user, and finally it may contain a portion of the model.
Whatever are the capabilities assigned to this controller, its role in the app flow and its interface towards the rest of the code is so well defined that we are able, in many cases, to give it the shape of a brick and place wherever we want in our app.

One of the simplest brick examples is the “SplashScreen” brick. A splash screen can be implemented in many ways inside an app, so we have no real need to provide it as a view controller object, but we recognize in it the characteristics required by a brick:
– well defined functionality
– restricted interaction with the app flow
– some degree of UI customization.
The functionality is quite simple: fill the iPhone screen with a fixed image for a given time, w/o any user interaction. The customization is limited to these two parameters: image and duration. Finally the interaction with the app is quite simple: inform it when the time interval specified as duration has elapsed.

Usually a splash screen appears when the app starts-up, so the easier place where to put it is inside the application delegate. A code example is the following:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// logs welcome to console
NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@”CFBundleDisplayName”];
NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@”CFBundleVersion”];
NSLog(@”Welcome to *** %@ v%@***”,appName,appVersion);

// customize splash
[splash setDelegate:self];
[splash setDuration:2.0];

// show splash
[window addSubview:[splash view]];
[window makeKeyAndVisible];

// run something in the background if needed

return YES;
}

Where the splash instance is an IBOutlet of a custom ViewController defined in the MainWindow.xib NIB file. So when the main NIB file is loaded we get the splash loaded too.
The image parameter is customized directly in the SplashBrick.xib file (we don’t want to do all programmatically; we are strong supporters of NIB files so we try to represent graphical information as much as possible using Interface Builder), while the duration is set using the setDuration: method. Finally we provide an extra parameter, that we call here delegate but it’s not a real delegate because it doesn’t provide as all delegates an extra functionality to the class, but it’s more an observer. Anyway we decided to use the delegate term in order to provide some common behaviour to all bricks.
The role of this delegate/observer is essential: it will be informed by the splash controller of the expiration of the duration time. This is what the splash can do only, as it has no control at all of the application loop. At this point the observer, once notified of the splash termination, knows how to react to this event and can decide what to do. In our example we simply decided to remove the splash and setup a new tab bar controller. This is the real starting point of the app: from now on the splash will be disposed of (and in fact its instance can be released thus freeing the space allocated to store the NIB and the image).

// splash finished: continue the flow from here
-(void)splashDidEnd {
[self setupTabBarController];
}

// setup tab bar controller structure
-(void)setupTabBarController {

// initialize
tabBarCtrl = [[UITabBarController alloc] init];

// … here follows the tab bar controller setup …

// add to window
[window addSubview:[tabBarCtrl view]];

// remove splash
[[splash view] removeFromSuperview];
[splash release];
}

Of course we can add a more complicated logic by letting the app delegate to run some initial setup in a background thread and then remove the splash screen only when this setup is over. So the splash duration takes the meaning of a “minimum duration”.

The main splash methods are here:

-(void)viewWillAppear:(BOOL)animated {
NSTimer *timer = [NSTimer timerWithTimeInterval:[self duration] target:self selector:@selector(timerFireMethod:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

– (void)timerFireMethod:(NSTimer*)theTimer {
[delegate performSelector:@selector(splashDidEnd)];
}

When the splash appears the timer is started. When it fires the observer will be called using the splashDidEnd method.
Of course we could have improved the robustness by checking for the app to be able to run the selector and providing an “exit strategy” (probably a basic exit(1); statement!). Or we could have provided a loadView method to setup the splash fully programmatically. Or else… this depends on your needs.

Next posts we’ll present some more complicated examples: how to make a “Credits page” brick and how to make a “Cached URL” brick (this one is a pure modeling brick).