Jan 27 2010

Handling Your Initial View Controllers for iPhone

Programming starts with a

design

A lot of webpages and articles talk about how to program, but they don’t talk about how to design a program. Good program design separates the weekend programmers from the professionals. Sure, anyone can piece together a working application but a good design allows a power and flexibility of adding new features, for example, without having to recode half of your application.

Here, we’ll talk about handling your initial views when your iPhone application loads. This might be a simple task if your application is simple, but take the case of having a welcome screen followed by a login screen followed by a tabbed view controller. You might set it up so that one activates the other upon being dismissed itself.

Here’s an example of how the process might look:

Program loads AppDelegate

Load Welcome view from AppDelegate

Dismiss Welcome view -> Tell Welcome view to load Login view

Dismiss Login view -> Tell Login view to load Tabbed view

What if you had to add a view or remove one, say if the login was no longer needed if you gave your users the option to save their credentials. You’d have to rewrite two different view controllers at least. And this is just a simple example so you can see how complicated this chain of views would get once your application grows. For most programmers this way is fine, and sadly enough most of the time, this is the way it’s done. But true programmers are lazy. Lazy programmers are good programmers. So be lazy and write good code so that when (not if) you go back and edit your code, it’ll be a snap.

A design starts on paper

Your programs should be conceived on paper. Even with applications that attempt to do this, I still find paper the ultimate programming tool (even though I did the one below on a computer).

Class Diagram

Class Diagram

First off, your controllers should be logically separated based on their tasks that they need to accomplish (not based on how the user will view them). So, you should have a controller or controllers to handle logging in and session creation and have appropriate UIViews and UIViewControllers to get and display info to your user. This may not be a one-to-one relationship though. For example, you may not have a UIViewController that’s associated with creating your sessions at all.

Next you will have your application’s business logic view controllers, controllers and all that jazz. The controllers sit independently to the view controllers except, of course, where there’s coupling or interaction. They are not tied directly, or rely upon any particular view. You illustrate those connections on paper (or in this case in the example diagram above). So if your “Add New Event” feature, let’s say, needs access to the session data, draw a line from your SessionController to your EventsController with an arrow pointing in the direction of the flow (from EventsController to SessionController in our case since the Events controller needs to know about the SessionController but not vise versa).

Abstraction solves everything

Since your controller code should be independent of how your views are laid out, you won’t have your AddNewEventViewController (the view that lets the user add an event) handling the actual creation and saving of events but will instead gathering and packaging the information taken from the user and given to an EventsController to handle the manipulation. Who knows, you may have several views that edit an Event in one way or another and if you change something in how the Event is saved, you’ll have to go into the code of each one that touches Event and rewrite code — exactly what we’re trying to avoid.

Abstracting the data in this way is called indirection and “All problems in computer science can be solved by another level of indirection;” — David Wheeler, except as Kevlin Henney says, “…except for the problem of too many layers of indirection.”

Singletons, under used

and under appreciated

So, you should have a session controller that sits somewhere ready to be called by who ever needs to validate a session or login (those views that would need access could be your tabbed views, could be your app delegate when your app starts, or could be in your settings views where you type your login info or when you log out). This is usually accomplished with a singleton class where any controller can access that one (and only) instance of your controller without having to pass around references to that controller. It not only cleans up your code, but also helps data integrity by not allowing multiple objects to edit the same data.

Handling your initial views

You should really have a separate controller handle organizing your views rather than the app delegate since the app delegate should really only be used to initialize your app and handle delegation of your application, not controlling business logic. So the structure should look like:

AppDelegate -> MainViewController -> LoginViewController

I like to have an overall MainViewController that handles all the subviews, be it a tab bar view controller, a table view controller, or whatever your main view is going to be. This level of indirection allows you to easily change what your main view controller is later, should your requirements or ideas change. Having said that, the MainViewController is going to need to get and maintain a reference to the application’s window.

To actually add the views, stack them on top of each other. Add the Tab Bar Controller’s view to the Window’s view first, then if needed, add your login views after that to stack them on top, and then remove them as needed when you’re done with them. By removing them from the top, it reveals the bottom view.

In MainViewController’s implementation file, your viewDidLoad: will look like:

- (void)viewDidLoad
{
[super viewDidLoad];
[mainWindow addSubview: tabBarController.view];
[mainWindow addSubview: loginViewController.view];
[mainWindow addSubview: welcomeViewController.view];
}

Where mainWindow is an IBOutlet to your Window in your MainWindow.xib file (or you could get it programatically if you prefer). Also, loginViewController is a pointer to your view controller that you put on top of the tab bar controller. On top of your login view, put a welcome view displaying any text, graphics or video to show after your application loads; note that this is different from your Default.png initial image. Then when you’re done with your login view, call removeFromSuperview on them to remove them from the view stack. So something like this in your MainViewController (since it handles all manipulation of your main views):

- (void)removeWelcomeView
{
[welcomeViewController.view removeFromSuperview];
// Any other code you need to clean up after your welcome view is removed
}
- (void)removeLoginView
{
[loginViewController.view removeFromSuperview];
// Any other code you need to clean up after your login view is removed
}

Obviously, when you remove the welcome screen view, under it (since you added it on the stack before the welcome view) is your login view. Then, removing the login view will show the tab bar view since that was added first in your view stack:

(Top)

Welcome View

Login View

Tab Bar View

This way we’re loading all of our views at once and stacking them so the one on top hides the one below. This has a slight overhead since you’re adding all your views when your applications starts but you can always delay adding the tab bar controller to the Window’s view until all the initial views are removed, for example. Then, if you’d like, using the MainViewController, you can add views on top of the tab bar view during execution, for example if you need to login again.

There are a few different ways to handle multiple views and each case is different. This is just one idea, with a few general guidelines. Feel free to ask any questions in the comments if anything wasn’t clear enough.

Sample Code

The following sample code is provided as is for educational and demonstration purposes. I threw it together really quickly and is only used to demonstrate the use of a MainViewController. Normally, you’ll want to make your MainViewController a singleton class, but in this example I passed the MainViewController instance to the subviews in order for them to call different methods on MainViewController to change the current views. By using a singleton design, you can avoid passing around this reference since there is only ever one MainViewController.

Also, this code demonstrates how to create a tab bar programmatically. It needs to be the root view of your window, but that doesn’t mean it needs to be the root view controller. We are still allowed to use a MainViewController as our root to handle all subviews and their controllers.

Download sample code (2010-02-11_TabBarTest.zip)


Jan 16 2010

How to Program for the iPhone – A Plan

This is not so much how to make applications for the iPhone, since there are so many on of those on the web already. This is more a syllabus on how to get started with the vast amount of information already out there and where to start from to quickly become proficient at iPhone development without getting frustrated or discouraged.

Development Requirements

An Intel-based Apple Mac
$99 (optional – if you want to actually publish your app)
That’s all!

Apple Developer Account

Development for the iPhone is initially free. So feel free to head over to http://developer.apple.com and sign up for a developer account if you don’t already have one. This will give you access to the Integrated Development Environment (IDE) called XCode, which is required to develop applications for the iPhone and iPod Touch. It also serves as a treasure chest of free information, sample code, tutorials, how-to videos and news, all of which I’ll talk about how to use later.

Once you’ve signed up for a developer account, you’ll need to download XCode and install it on your Mac. PC users are, as they always are, out of luck since a Mac is required for development. Once that’s done, put it aside as you won’t need it for a bit.

Learn to Program

An Important Design Pattern: Model View Controller

If you already know how to program a little bit, but haven’t gone through the rigors of a four year university Computer Science degree or something similar, start with learning an important design patterns, namely one called Model View Controller (MVC). Of course, a 4-year degree is not necessary, but you need to understand basic software engineering principles, design patterns and basic usability practices, which practically none of the programming tutorials, books and online articles teach. Also, a lot of practice helps as you’ll learn how to fix non-obvious compiler and runtime errors, how to structure your code, and pitfalls of each language you use.

Objective-C: The Language of Choice

After you understand the basic principle of MVC, you can then move on to learning the language of choice, Objective-C. Why Objective-C? Why didn’t Apple just choose a common language like C++ or Java? The reasons will become obvious as you learn about the language, it’s power, and how it fits into the MVC methodology better than any other language you’ve likely seen before. So here’s a nice tutorial on how to program in Objective-C.

If you already have a great understanding of programming and know a C-based langauge, skip the lengthy tutorial and take a look at this primer to get a sense of the additions to C that Objective-C brings to the table. For most people who are familiar with a C-based language, this will be all you need to get started.

Continue reading


Oct 19 2009

Dynamic Textfields in Flash AS3 and Their Bugs

I do a ton of localizations for web-based media (over 30 countries) and have run across several bugs in Flash where the characters don’t show up for certain fonts, especially for translations with non-latin characters (such as Russian, Chinese, Japanese and even Hungarian and German). I always complain about them, and instead of just complaining, I figured I’d share some of the solutions since they’re bugs in Flash and may not have obvious solutions.

Obvious Solutions

The obvious solution when you have a dynamic text field, that is either driven from XML, RSS, or other external document or data source, is to embed the font’s character sets. Obviously if you are going to be using Korean in your Flash application, you want to embed the Korean character sets so the Korean characters show up in the font you have chosen. However, with so much emphasis on branding these days, not all specialized fonts have characters in Korean.

For example, the Star Wars Jedi font that I once worked with has absolutely no other characters beyond A-Z, a-z and numerals. Forget Spanish and it’s tildes, forget German and its umlauts, but Russian?! Ha! Everyone knows there were no Russian Jedis! So, what to do?
Continue reading


May 30 2009

Custom Mouse Cursor for ActionScript 3

I threw together an FLA for someone to show them the different ways to handle custom mouse cursors in ActionScript 3 (AS3). I figured I should start posting more of my code for people since I use other people’s blogs all the time to figure out my own problems.

I’m mostly coding up stuff for Flash, Flex, Augmented Reality, iPhone, PHP, and CSS/HTML right now so hopefully I’ll have the time to post more snippets of things I’ve figured out trying to get all this technology to work.

This movie requires Flash Player 9

Direct Access to the X and Y Mouse Coordinates

The first method allows us a finer control over the movement of the cursor by directly changing the X and Y coordinates of the cursor movieclip with the X and Y coordinates of the mouse. If we wanted to restrict the movement to say, a specific Y coordinate (as we’ll see in the next example), we can do that just as easily by keeping the target_mc.y a constant when we update it’s X coordinate.

// Set up our listeners for each of our mouse actions
boundary_mc.addEventListener( MouseEvent.MOUSE_OVER,
onMouseOver );
boundary_mc.addEventListener( MouseEvent.MOUSE_OUT,
onMouseOut  );
// Ignores all sub movie clips and treats them as the parent
//      — otherwise events will be triggered on the child
//      movieclips and not our main clip
target_mc.mouseChildren   = false;
boundary_mc.mouseChildren = false;

// Ignore all the mouse events for the cursor
//      — otherwise MOUSE_OUT will trigger since mouse is
//      now on target_mc instead of boundary_mc
target_mc.mouseEnabled = false;

///////////////////////////////////////////////////////////////
// ON MOUSE OVER /////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When the mouse rolls over onto our red boundary, hide
//   mouse/show cursor
//
function onMouseOver( theEvent:MouseEvent ):void
{
// Swap the mouse for the cursor
Mouse.hide(); // hide mouse cursor
target_mc.visible = true;

// Add a listener to handle the moving of the mouse
// We add the listener here because otherwise the onMouseMove
//    would execute whenever the mouse moved, whether it was
//    on our boundary or not. Not a big deal, but better for
//    efficiency
boundary_mc.addEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion );

// Handle the movement now so we don’t have to wait for a
//   mouse movement to reposition the cursor
onMouseMotion(null);
}

///////////////////////////////////////////////////////////////
// ON MOUSE MOTION ///////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When the mouse moves, we also want to move our target to follow
//   the mouse
//
function onMouseMotion( theEvent:MouseEvent ):void
{
// Reposition our custom cursor
target_mc.y = stage.mouseY;
target_mc.x = stage.mouseX;
}

///////////////////////////////////////////////////////////////
// ON MOUSE OUT //////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When mouse goes outside our red boundary, show default mouse,
//      and hide our custom one
//
function onMouseOut( theEvent:MouseEvent ):void
{
// Swap the cursor for the mouse
Mouse.show();
target_mc.visible = false;

// Stop listening for mouse movement
boundary_mc.removeEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion );
}

The Drag and Drop Method

Our next method uses the drag function built into Flash. With this function you can drag a movieclip around the stage with the mouse automatically. This restricts some of our freedom, but gives us some very easy coding to control the mouse cursor to specific regions. In this case we simply restrict the motion of the cursor along a rectangle of 0 height (so it won’t move along the Y axis) and with a width as wide as our boundary box. This feature has its advantages, and I merely include it to demonstrate how to use it in the context of a custom mouse cursor.

// Set up our listeners for each of our mouse actions
boundary2_mc.addEventListener( MouseEvent.MOUSE_OVER,
onMouseOver2 );
boundary2_mc.addEventListener( MouseEvent.MOUSE_OUT,
onMouseOut2  );
// Ingores all sub movie clips and treats them as the parent
//      — otherwise events will be triggered on the child
//      movieclips and not our main clip
target_mc.mouseChildren    = false;
boundary2_mc.mouseChildren = false;

// Ignore all the mouse events for the cursor
//      — otherwise MOUSE_OUT will trigger since mouse is
//      now on target_mc instead of boundary_mc
target_mc.mouseEnabled = false;

// Calculate the the vertical center of our boundary
//   so that the cursor can move along that line
var verticalCenter_num = boundary2_mc.y + (boundary2_mc.height / 2);

///////////////////////////////////////////////////////////////
// ON MOUSE OVER 2 ///////////////////////////////////////////
/////////////////////////////////////////////////////////////
// Same as our previous one, but set for another boundary
//
function onMouseOver2( theEvent:MouseEvent ):void
{
// Swap the mouse for the cursor
Mouse.hide();
target_mc.visible = true;

// Add a listener to handle the moving of the mouse
// We add the listener here because otherwise the
//    onMouseMove would execute whenever the
//    mouse moved, whether it was on our boundary
//    or not. Not a big deal, but better for efficiency
boundary2_mc.addEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion2 );

// Handle the movement now so we don’t have to wait
// for a mouse movement to reposition the cursor
target_mc.y = verticalCenter_num;
target_mc.x = stage.mouseX;
}

///////////////////////////////////////////////////////////////
// ON MOUSE MOTION 2 /////////////////////////////////////////
/////////////////////////////////////////////////////////////
// Restricts the movement of our custom cursor along the X axis
//
function onMouseMotion2( theEvent:MouseEvent ):void
{
// Calculate the the vertical center of our boundary
//   so that the cursor can move along that line
var verticalCenter_num = boundary2_mc.y +
(boundary2_mc.height / 2);

// We use startDrag() here since it’s easier to restrict
//   the cursor’s boundaryusing a Rectangle object.
// boundary2_mc.x: Start from the x position of our
//   boundary verticalCenter_num: Start from the
//   vertical center as our y coordinate
// boundary2_mc.width: Allow the cursor to move
//   the length of the boundary’s width (starting from x)
// 0: Don’t allow the cursor to move up or down
target_mc.startDrag( true, new Rectangle(
boundary2_mc.x,
verticalCenter_num,
boundary2_mc.width,
0)
);
}

///////////////////////////////////////////////////////////////
// ON MOUSE OUT 2 ////////////////////////////////////////////
/////////////////////////////////////////////////////////////
// When mouse goes outside our gray boundary, show default mouse,
//   hide custom mouse and stop drag
//
function onMouseOut2( theEvent:MouseEvent ):void
{
// Swap the cursor for the mouse
Mouse.show();
target_mc.visible = false;

// Stop our drag
target_mc.stopDrag();

// Stop listening for mouse movement
boundary2_mc.removeEventListener( MouseEvent.MOUSE_MOVE,
onMouseMotion2 );
}

I hope the code is commented well enough for you to understand what’s going on. It should be fairly self explanatory, but if not, feel free to ask.

Sample Code

Below is the source code for the SWF used at the top of the post:

Download the Custom Cursors sample code.


Jan 29 2009

Fixing What’s Not Broken: A User-Centric Perspective

The saying, “If it ain’t broke, don’t fix it,” is not a very good motto, especially when there’s progress to be made. When you’re working with old and tired technology it really drags down your capabilities and your ability to move forward. The need to keep around legacy solutions only holds back your clients from realizing your full potential as a company.

Their Failure is My Failure

Being the Technical Director at my company means that I get to pull out all the stops when it comes to investing in our technical capability as a company. But it also means that I am responsible for those technological failures as well.

Coming from the world of Human Computer Interaction (HCI), the user is never wrong or stupid, but instead it is your design that is wrong or inadequate and the sooner you realize that, the sooner you can move on to building better, more functional and friendly software.

The same goes for my developers. They are forced to use the solutions I provide for them and if they have problems with it, break it, or can’t get it to work, that’s my failure to design a well-working platform for them to develop on. Sure, I can always fix the problem for them in a few minutes and show them where they were misled because I understand how all the pieces fit, but I’m the one that made it, so of course I understand it. I could dismiss their problems as them not knowing how the code works or that certain things need to be placed in particular spots for things to work properly, but that’s not their job. Their job is to develop really great pieces of work and it’s only a difference of mentality on how they should do their jobs better and easier.

On the one hand, I could produce documents and try to explain how everything works and occasionally field questions on how certain things work. The alternative is to pay attention to the problems they’re running into and resolve it in a way that’s best for them. This may require a higher initial investment, but it’s an investment that’ll yield higher returns in the long run, not to mention happier developers.

It’s Not Them, Stupid, It’s You

We’re quick to fault others for something that we ourselves may understand quite well, but with the wealth of diversity in this world, no one can know exactly the same things you do. I work with really talented people and I can’t blame them for not knowing things I think are common sense because I know they know things that I couldn’t even begin to grasp. So instead of trying to be superior to people or trying to absolve yourself from blame, take the stance that the end-user is always right, be it your co-workers, your clients or your customers. Remember, you’re not trying to compete with them, you’re trying to work with them.

Don’t Fix It, Improve It

Take something in your line of work that is tired and old and revamp it. If your software is coded in ActionScript 2, upgrade it to 3. If your website is made with just straight up HTML, refactor it to include CSS and some JavaScript. If your invoices are still written in the Courier font, hire a designer to make them less intimidating (unless that’s the point, in which case your business model is flawed if you’re constantly trying to convince your customers to pay up). I know it might not seem broken and may seem to work fine, but by improving on what you already have, it allows you to evolve and be a leader rather than having tired old things hanging around and weighing you down.