Rapture In Venice, LLC

:: Freelance iOS Development & Team Augmentation

Smart Stacks v1.0 for iPad Released!

Pleased to announce that Rapture In Venice, in partnership with Patrick Hansen, has released Smart Stacks, a kids’ educational flash-card app exclusively for iPad!

It’s been 6 months in the making and work on it came after all my full-time *and* client work. But, with both of us equally busy, we executed and got it done and we’re both proud of it! We hope you give it a shot with your kids to help them learn words, pictures, and even multiple languages!

The Smart Stacks site can be found here with more info!

  • Print
  • Facebook
  • Twitter

, , ,

Interface Builder: Don’t Know What You’ve Got Till It’s Gone!

Much like when Joni Mitchell riffed on the paving of paradise, Interface Builder is the pariah of iPhone developers. I’ve seen it when it’s fouled up its internals after you’ve spent hours trying to figure out why a simple button event isn’t firing. I’ve faced having to merge the dang thing when working with another developer — yeah, good luck with that! I’ve seen conference sessions on how slow it is to load XIB’s. Interface Builder is the bastard step-child of iPhone development.

Well, speaking personally, I’m so sorry Mr. Builder.

My last three projects have all been done using the Three20 platform: Sports Authority Fit, Fuzz Alert, and one other that has yet to be released so I can’t tell you no matter how much Goober Grape you offer. If you’ve never developed with Three20, it does have its rewards, but one thing you’re taught to do is to nix Interface Builder and build all your UI by hand.

Building UI by hand is easy to accept if your app has screens dominated by tables or single components like photo browsers. However, when you have intricate screens with full-on interfaces, it’s horrifying to position components, hook up delegates, set text field and label properties you barely remember, and so on. HORRIFIC! There are ways to integrate XIB’s with Three20, yes, but we found them a bit error prone early on and it’s really not the spirit of the platform since it offers its own components like TTButton, TTImageView, and so on.

Anywho, I’d done manual UI before and while it was a little irksome at first, I got used to it as the projects wore on. These projects span about 5 months now. Following this, I decided I would quit Three20 and go back to natural iPhone development. My partner in crime and I created iBoost as our alternative. (I’ll let the README speak for it.)

So now, I’m back to the XIB world and today was the first day where I actually got to work with ole’ IB again. And, wow! Aww, baby, I missed you so much! Being able to drag buttons in to a view and set all the properties visually. No crazy rectangle math! And — OOH OOH — being able to set those pesky rotation flags to support landscape! It’s all so easy!

In fact, I was so excited, I’m even letting the XIB’s live side-by-side with the View Controllers now. No separate group for them, they are flying first class in my new standards!

So, all you iPhone developers out there down on Interface Builder, take it from me. Appreciate it! It could be worse. You could have to use Android’s UI builder. (HINT: nobody wants to!) You could even have to use Flash Builder’s abominable UI designer!! (HINT: run for the hills!)

So, before you go to bed tonight, give IB a hug. Tell her you appreciate all she’s done. Close her down and let her rest before you go to bed.

Don’t it always seem to go that you don’t know what you’ve got till it’s gone?

  • Print
  • Facebook
  • Twitter

Overriding Your iPhone’s Localization In-App

For my upcoming flash card app for the iPad, I had the unusual challenge of needing to be able to change the app localization based on a user’s selection rather than just depending on the language globally set by the user on their iPhone. The reason is that I want the user to be able to change the language of the flash cards independent of the iPhone as a way of learning new languages.

Now, one thing I knew I wanted to do was to be able to leverage the Localizable.strings files so that I could keep a consistent, localized format for my strings. It would be easy to keep the list of flash card strings programmatically, but it seems silly to store these strings in a different format or write my own class to process the Localizable.strings` format.

So, how does one access a specific localization file? If you’re like me and always supporting localized resources, you are familiar with the NSLocalizedString method. If not, here’s how you use it to support localized strings:

flashCardLabel.text = NSLocalizedString(@"Apple", nil);

Your app will automatically swap in the appropriate string based on the key you provide. (The second argument is ignored in code but used as a comment when processed by genstrings, which I choose to set to nil.) If you Command-Double Click NSLocalizedString, you will find that it’s actually simply a macro for calling an NSBundle method:

[[NSBundle mainBundle] localizedStringForKey:key value:@"" table:nil]

This is the key to our solution. There are actually some other methods we an use instead that don’t force us to use the main bundle which is wired to give us strings based on the iPhone’s locale!

To accomplish this, we first have to load the bundle we need. Here’s how we do it:

// find the path to the bundle based on the locale
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
 
// load it!
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

The trick to initializing the bundle is to make sure you do not specify a filename. That tripped me up for a while.

Now, you can retrieve your localized string using NSLocalizedStringFromTableInBundle:

NSLocalizedStringFromTableInBundle(@"Apple", nil, spanishBundle, nil);

NSLocalizedStringFromTableInBundle lets you specify the specific bundle to pull from, though you do need to explicitly specify nil for the tableName. (This is hidden from you normally.)

Now, you can take this code, handle the bundle loading in one place, and simply make that final call whenever you need to know a specific, localized string. I recommend making your own macro as well since the 4-argument can make it tricky to remember the argument order. :-)

Enjoy your manzana!

  • Print
  • Facebook
  • Twitter

, ,

Rapture In Venice’s Development Process

I’ve worked with small companies and large, startups and huge corporations, and in addition to working as an independent consultant I’ve formulated my own personal software process that I’d like to think is a nice mix of all the best features of what I’ve experienced before and imagined on my own. And so I’d like to share it with you.

My Philosophy

My process is a lightweight process overall, but includes elements many might consider part of a more “structured” methodology. Most notably, while I’m a huge Agile advocate, dealing with change simply must be considered a reality in software production, I also believe in upfront design and documentation. When working with 90% of the clients I’ve worked with, documentation (of varying sorts) is simply necessary to get the job done, and I don’t think it’s realistic (or desirable) to be working with the client directly on a daily basis and calling that “being agile.” It simply doesn’t work and you can’t rely on the client having time to chat with a developer.

Pre-Production

The first thing I do is meet with the client, discuss at a high-level what they’re looking to have done, and if I feel I can solve their problem I give them a very rough, general price range for what it will take to get it done. I usually stick to a fairly sizable price range to try to avoid any surprises, but there’ve been a couple instances where the final contract ended up a little higher, or even a little lower, than the estimate.

If the client wants to move forward, a user research period begins where I might do any of the following:

  • Determine what technology should be used to solve the problem.
  • Gather up resources to get it done, from software to humans (perhaps a designer).
  • Get agreement on a time schedule for getting things done.

That last part, creating a rough schedule, is important for me. I’m not a full-time consultant, I’m part-time. So, I have to get agreement from a client that the app they want in one week might take three weeks. The clients I work with are those that have smaller tasks or, themselves, are undertaking the project part-time. It’s just an agreement that needs to be made.

The next step is what I dub “The Summit.” I like to get everyone involved with the project in a room, in person, and talking requirements. This is where platforms and technology are hashed out, but we also discuss what the app will do. Often times a server developer is involved and it’s good to make sure they’re on board now rather than later! Also, I like to talk about the app screen by screen, it helps to get people focused on what they want the app to convey and look like, and unless you’re working for a large software maker, there’s no need to keep requirements TOO high level that you can’t talk about specific screens. There’s also the benefit that clients are always talking more specifically about how the app should look and trying to keep them away from that level of abstraction is likely not to be received with pleasure!

After this discussion, and any followups that may be needed to hash out additional details, I create the initial functional specification. This document lists out everything the app will do based on the requirements and additional ideation. It includes algorithms, how complex fields are formed, and anything that I would need to tell *another* developer to get the job done. In the Agile community this is often ignored and it’s a HUGE mistake. If you’ve ever written software and found you often didn’t know what each screen was supposed to display or how it was supposed to behave, and you had to keep going back to the client for more and more information throughout the ENTIRE project, you are probably missing a functional spec.

The spec doesn’t mean change can’t happen. Change ALWAYS happens. The difference is that when change happens, you update the spec! It should always reflect how the app is supposed to work. The reason is that ad hoc discussions between developer and client don’t do anything to help everyone else who needs to know how the app works: project managers, designers, marketing, and especially testers!

Another thing. The spec should be created by you and not the client. If the client creates one, you can use it as a basis for your own, but in general the client’s spec will not include the details you need to get your job done. Software is about details. That’s why the technical person should be in charge of the spec!

The spec and the SOW (Statement of Work) are submitted to the client, iterated on, and signed off. Next, to steal a term from Joel Spolsky, it’s time for Butts-In-Seat. GO!

Butts-In-Seat

With research done and spec in hand, implementation begins. There should be no questions about payment or what the client wants at this point. Your butt is at your desk and you are writing code. In theory, you should be able to go long spans of time without needing to speak to the client if it comes to that. In general, I like to give clients daily updates during the “buildout” phase. I call the time between when the app is started (File/New Project) and when there’s minimal functionality enough to actually be able to run the thing (My tweets are being retrieved!) as buildout.

Once buildout is complete, I focus on adding in all the functionality, fixing bugs along the way, until I get to a functionally complete Alpha product. Alpha is usually a small phase which basically means fixing any show-stopper issues that prevent the client from seeing ALL of the functionality. At that point, it’s Beta and we go into a full-time testing cycle.

Testing

Testing involves using the app, verifying the app, and making sure it matches the spec. During testing is when you’ll also see a lot of change. Now that the client can use the app like a real user would, they (and you) will notice user experiences that simply don’t work well. I’m usually very liberal with clients when it comes to change of this matter.

When it comes to new functionality, however, I am sure to be very strict on the matter. What I like to do is add the new feature requests to a list that we can come back to when testing is done. At that time, we negotiate what features I’m willing to add for free, but which will require additional cost. At this point, another SOW may be called for, but it’s never an iterable thing. The app has to be released after all and the client is eager for that to happen.

Post-Production

As a mobile developer, post-production entails taking care of the release to the Apple Store (or Android Market, etc.) for the client. Any major bugs that are reported early get folded into a point release that I like to have pushed to the users sometimes just a mere few days after release. With so many devices to mind over (yes, even with iOS these days), there’s usually some hiccup at the beginning. No company is immune, so just accept reality and be prepared for it. :-)

I hope this little discussion of my process has been helpful!

  • Print
  • Facebook
  • Twitter

Is an Objective-C Minifier Possible?

My coworker-friend-buddy, Sean, and I are putting the final touches on our iPhone framework, iBoost. One thing we have to think about now is how it will integrate with our (and your) applications. There are two basic strategies I’ve seen:

  • Copy the source code into the project. This is never done with Java projects, but is always an easy choice for C-based systems because compiled code is platform dependent. This is a very common choice for small classes, too. I make a lot of my mini-modules available this way.
  • Compile as a library and copy header files. This involves distributing as a compiled library with header files. Flurry does this, as well as AdMob. The obvious motivation is to keep the source a secret.
  • Obviously, if wee distributed iBoost as a library, it wouldn’t be to keep the code secret (since it’s open source), but it’s still a valid way to go.

    I lean towards the former. Dumping the source into your project may seem messier, but if you keep it isolated in a directory instead of copying it to your Classes, it’s really no different than library distribution. Plus, as the SDK iterates, and different platforms become available, you don’t have to worry about updating your libraries all the time. I just recently had to do this with the Acapela Text-to-Speech library and it was doubly painful because they are located in France and I needed it immediately. :-)

    Minification

    But now I have a new thought. It seems messy to distribute source as a large group of files. I’d love to make it a two-file (*.h and *.m) distribution. Hell, one would be great if it’s doable. But how?

    Well, if you’ve been involved with the JavaScript scene the last few years, the little trick we like to do when publishing websites is to run a “minify” on the JS code. This is a script (there are several out there, but the YUI version is used a lot) that takes your JavaScript code, cuts out as much whitespace as possible, and basically runs your code through a vacuum. The resulting code is often unreadable, but (hopefully) works exactly the same. The idea is that you not only save some bytes of bandwidth, but it makes it a little harder for people to snoop through your code which is obviously uncompilable.

    So, it is possible in Objective-C? I can’t find any references to it. No one seems to have done it. My guess is it’s doable. Here’s my theory on how it could work:

    1. Append all of the header files together.
    2. Pull out #import’s referencing any of the files themselves.
    3. Add forward references (@class) for all classes at the top of the file. (No need to ull existing ones unless we want to keep the file size minimal, which is not necessary.

    I’m going to attempt it this week with a Python solution. I’ll let you know the results. What do you think?

    • Print
    • Facebook
    • Twitter

    , ,

Previous Posts Next posts