Tuesday, July 26, 2011

Road to devLink: View Controllers, Web View, Services, and Tests

I am writing this post after pushing the following commits:


iOS App: a862663

Server: N/A


Open Terminal, navigate to a nice place where you would like to store this code, and then perform the following to view this commit

git clone git@github.com:danielnorton/CandyStore-app.git --branch development
cd CandyStore-app/
git checkout a862663

In this commit, I have set up the main view controllers of the iOS app, I have also set up the first vestiges of a few of the services that the app will use, and I have written a few unit tests.


View Controllers

You will see that in MainWindow.xib I have set up a UITabBarController with three tabs. Each tab holds a UINavigationController that then each hold one of the three root view controllers that represent the three distinct sections of the app (My Candy Jar, Candy Shop, and Candy Exchange).


In my devLink session, I will probably discuss this approach. I have the idea in my head that I will have this completed app and then do separate branches or something like that to implement discrete portions of the app that are pertinent to the topic at hand. So, when I am talking about view controllers, I will (in advance) create a branch of the completed app that does not have this initial setup built. Then we can step through creating tab view controllers and navigation controllers, etc. We can see how to wire them up in Interface Builder and talk about how every thing that is done in Interface Builder can be done in code.


Services

As discussed above, there are three tabs. If a user is not currently subscribed to the Candy Exchange and they tap on the Exchange tab, I would like for the app to alert them to visit the Candy Shop and subscribe to the exchange. To facilitate this, I have registered the app delegate as a UITabBarControllerDelegate. That will notify me when the tab is tapped. All of the logic to test the current state of the user’s subscription and decide if the app should notify is contained in a service. At the moment, there isn’t much logic in the service. It will probably get more fleshed out as I add a model and wire up to In-App Purchasing and my own web services. But for now, I can still build the concept that some amount of work needs to be done, and that work needs to be contained in a service. When the complexity comes later, I can change the service without having to do much work (if any) outside of it.


When the service communicates back to the app delegate, the app delegate will display a UIAlertView. When all you need is a to display a modal message to the user, it gets somewhat tedious to fill in the big init method on UIAlertView. For situations like this, I am a big fan of categories. I have created a category for this situation called UIViewController+popup. I will use this at devLink as an example of categories and how to use them.


... hmm ... I have used UIViewController+popup in a number of projects. It’s one of my little “toolbelt items”. While writing this post, the thought occurred to me that tying the popup method to a UIViewController is not necessary ... I will leave it there for now. Maybe somebody at devLink will catch it and start a good discussion.


Tests

I am a big fan of TDD, but to be honest, I am not rigorous about using it. Additionally, I don’t find the testing tools built in to Xcode to be very good. The mocking tools I see out there aren’t terribly impressive to me, and I have yet to find an IoC container / framework. So, I really don’t write a lot of iOS unit tests. But since part of this project is for my own education, I am going to make a new concerted effort. Since the services I am writing at the moment are still self contained this is working out pretty well. Here is an example of a test and, as tests go, an example of how to use one of my services (with a huge name that I don’t like typing over and over).

- (void)testShouldNotAlertUserPurchaseExchange_IncrementThree {

ExchangeSubscriptionNotificationService *service = [[ExchangeSubscriptionNotificationService alloc] init];

[service reset];
service.counter++;
service.counter++;
BOOL shouldNotify = service.shouldNotify;
[service release];

STAssertFalse(shouldNotify, @"should not notify.");
}

When I get a little meatier code, I intend on writing a post about my preferred coding style and how I like to structure the contents of the .m and .h files. service.counter++; violates my preferred style, but it works in this instance so I am not going to get all excited. My preferred style would end up as something like: [server setCounter:service.counter + 1]; which is kind of ugly in this particular scenario.


Web View

If a user has not yet purchased any candy, instead of showing an empty list for the Candy Jar view controller (the first tab), I would like to show a welcome view. I thought it might be helpful to demonstrate the use of a UIWebView in showing this welcome message. I wanted to build a single ... welcome.html ... file to embed in the app. I fumbled along with Safari Mobile CSS stuff and decided to punt and see if I could get some cheats from Dashcode. It turns out I was able to put together a rudimentary welcome view very easily in Dashcode. It only took a few minutes. I kind of liked it. It is not fancy, and it really doesn’t end up looking as whiz-bang as I wanted. I really wanted to build a thing that used multiple colors on a single line of text or something like that which would be difficult with UILabel. But, anyway, it will work for now. I will show that off at devLink. The web view is in My Candy Jar view controller. It includes a good opportunity to demonstrate a simple animated fade in for the web view when it completes loading its content. Also, this view controller will offer a good talking point of how and when to use a UITableViewController and when to use a regular UIViewController that implements UITableViewDelegate and UITableViewDataSource. For this controller, I chose the latter. This will also make a good talking point when introducing protocols and delegation in my devLink talks.


No comments: