I have seen a number of excellent posts that explain the differences between storyboards, nibs and code for creating UIs.
I have also seen (recently) people asking "should I only use nibs?" and exclaiming "I only ever use code to write my apps".
I thought it was about time to add my own thoughts and to provide a glimpse into how I used all of the tools available to create Emojicate. Hopefully it will show you how it's possible to get the convenience of storyboards with the reusability of nibs and the additional power of code to create your apps without having to compromise anywhere.
Something I see a lot of the time is people using one humongous storyboard file to do EVERYTHING in their app. That's how I first started using them too. For a lot of what I was doing that was fine but when I started adding logic to where the user should be (logging in, on-boarding, etc...) it quickly became a mess of pushes, pops and presents.
In Emojicate, the main part of the app (once you have logged in) is not that big and actually only comprised of a couple of different UITableViewController and UIViewController subclasses that are configured to show different content using different data sources. The "flow" of the app is managed with a UITabViewController and a few UINavigationControllers. This is contained in a single storyboard with a single point of entry.
Then there is the on-boarding/account creation "flow". This is very simple and contains a couple of screens for entering the user's name, selecting an avatar, finding some friends, etc... This is also contained in a single storyboard file.
The third storyboard is the "Compose" screen. While it is only a single screen it actually comprises of a couple of container views which work together to form the whole screen. This is something that I can't get with Nibs and coding it would be possible but also a pain setting up the child view controllers and the AutoLayout constraints. It also makes it easy to present the compose screen from different places throughout the app without having to have segues all over the place.
So the whole app has 3 storyboard files. Each with their own purpose and chosen to aid the creation of the app and improve maintainability of the individual, distinct "flows".
Flow (or workflow) is the key word here as I tend to use it as a way of defining the boundaries between storyboard files. The three workflows here are creating your account, browsing content and creating content.
There are several nibs for the entire project and most of them started out as being defined in one of the various storyboard files within several of the view controller scenes. This is actually part of the reason that they now exist as individual Nibs. I see Nibs (a lot of the time) as a way to refactor repeating parts of storyboards. The one part of the project that is particularly relevant is the cell used to display a post.
This nib was only interested in laying out the content of the four main parts of the Emoji Post Cell. The author's avatar and name, the "time ago" date label and the EmojiTextView.
This allowed me to delete all instances of the same table view cell defined in each of the multiple storyboard scenes and have a single definition of what it looked like.
Using the code...
UINib *emojiCellNib = [UINib nibWithNibName:@"emojiCell" bundle:[NSBundle mainBundle]]; [self.tableView registerNib:emojiCellNib forCellReuseIdentifier:@"EmojiCell"];
I was able to use the nib instead without changing any other code.
I could have coded this but again, the creation of the views, then the auto layout constraints take a lot longer than dragging and dropping onto a nib. The visual feedback from a nib allowed me to set it up and get it working almost instantly.
The final tool in the arsenal is probably the most powerful and flexible and should definitely not be shunned for nibs and storyboards but can be used alongside them with awesome results.
One of the main views used throughout the app is the EmojiTextView. The main work that this view does is managing the layout of an array of Emojis.
It looks like this, although it doesn't actually have a background at all.
The same view is used in a number of places. It is used in the main timeline views, the user profile view, the chat view and most importantly in the Compose screen.
All of the interaction and animation shown here is part of the Emoji Text View. It has some hidden "features" too. When we were developing the app we were unsure of how many emojis to allow for each message. So the whole app has a parameter to change this. The EmojiTextView will the resize and reposition the emojis according to the maximum number per message. It will also stop displaying the when it reaches the limit etc...
With all the interaction and complexity involved in creating this one UIView subclass it would be much impossible to create it in a nib. So all of the work done here is coded. The positions are calculated, the tap and pan gesture recognisers all interact to "shift" the emoji around when moving or deleting an emoji.
Another interesting class to look at while we're here. The Emoji itself is not stored as an image but as a class containing a "type" and other relevant information "date", "emojiImageName", etc... It then contains a method...
- (UIImage *)image;
This allowed me to store emojis not as images but as very lightweight bits of data that can be either loaded or rendered very quickly on the device when they are needed. In a way this is another UI that is coded.
There are definitely parts of this app that I'd like to revisit and improve. There are some parts that I still think are excellent.
However, all of it was created by using a combination of the tools available. To say that I'm only going to use nibs or I only use code to create apps would be throwing away a valuable tool. It would be similar to a joiner saying he is going to build his next table using only a screwdriver. While a screwdriver is excellent and driving screws and can be used (at a push) to bash in nails I wouldn't like to cut the wood to size using it.
For the people who only code their apps, while that may work for them I think it is important to get an understanding of everything available so that you can decide what to use and when and how they can complement each other.
Anyway, that's my two pence worth.