Recently I tried something I had feared for a long time: Using code to create my views instead of using the traditional storyboard.
Background
In any given iOS programming tutorial, you will most likely use storyboards to complete your task.
Examples:
- https://www.raywenderlich.com/114552/uistackview-tutorial-introducing-stack-views
- https://www.raywenderlich.com/122139/uiscrollview-tutorial
- https://www.raywenderlich.com/117249/watchos-2-tutorial-part-2-tables
Now, there is nothing inherently wrong with using storyboards. They're perfectly fine and get the job done with creating your UI...
Right?
While the first part of my statement above is true, storyboards sometimes fall short when working in bigger projects with many view controllers or in views that have many elements and subviews.
The Problem
My largest project right now had 20-30 view controllers in a single storyboard. Whenever I would open the storyboard, my ancient MacBook Pro would struggle to load the storyboard. I needed to rapidly iterate on my views based on changes in code and having the storyboard load time be 10 seconds+ wasn't an ideal situation.
Note: I later switched to using multiple storyboards which (mostly) eliminated this issue, however having multiple storyboards with storyboard reference outlets all over each of them is really confusing.
When a view controller in a storyboard has multiple views, selecting the correct one becomes difficult if they cover each other or reside as subviews. It is possible, but it's a tedious task that I wanted to avoid.
I also wanted to try something new, and killing storyboards sounded fun.
My Solution
Code is great. And if I'm already using some code in my projects, why not go "full code"?
But wait... No storyboards = no visible view until runtime... How am I supposed to iterate quickly when I can't even see what I'm working on?!?
Ages ago, I read an article on how a fairly large app open-sourced and detailed their design iteration process. They used Swift Playgrounds to see the controller in real-time as they modified the code. Brilliant, let's do that!
Okay... so how do I use auto-layout and constraints without a storyboard? Through some research, I found out how to use constraints inside code.
Swift 3 Example:
let view = UIView() // Create view object
view.translatesAutoresizingMaskIntoConstraints = false // Set this to false so this works as expected
view.backgroundColor = UIColor.red // Let's set this to red so we can see where our view is in our controller
self.view.addSubview(view) // Add our view to the view controller's view
// View created, constraint time:
view.heightAnchor.constraint(equalToConstant: 50).isActive = true
// Let's break this down.
// view.heightAnchor will set our view's height, as the name implies.
// constraint(equalToConstant: 50) Will set the value to an integer constant of 50
// isActive = true will activate our constraint
// Simple! Let's do the rest of the constraints:
view.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 1/2).isActive = true // Set our width to be 1/2 of the view's size
view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true // Center horizontally on the X axis
view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true // Center vertically on the Y axis
// And... done!
Let's take a look at our playground:
http://i.imgur.com/IRSyJLb.png
Awesome! Let's play around with these constraints and make our view appear at the top of the controller.
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.red
self.view.addSubview(view)
view.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/3).isActive = true
view.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
view.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
Here I've used a new item: topAnchor
Setting it equal to the view controller's view's topAnchor (that's a mouthful!) will cause our view to reside at the top of the view controller's view.
I've also set our width to be equal to the view's width, centered our view horizontally, and set our height to be 1/3 of the parent view's height.
Let's see what this did to our view:
So cool! In just a few lines of code, we've created a view at the top of our view controller.
To learn more on how to use these constraints, I decided to take an existing view controller created in my storyboard and re-create it in code.
I actually ended up creating a simple view controller/tool called "AccountController" that can be easily modified to show a login and registration page. Neat!
Here's a GitHub link for anyone who wants to try it out.
Also, feel free to modify it as you wish, it's under the MIT license! I plan on fixing some issues and improving on it over time, but feel free to fix bugs and improve it for me via pull request!
Thanks for reading!
FYI, I'm only 15 (almost 16!) so if my grammar or wording is poor, I apologize :)
Top comments (13)
Storyboards are cancer. No one should use them. Good article.
What else should we use?
if you're tired of giant storyboards, you can try using .xib instead. Alternatively you can make your views programatically.
I agree with what @maurandk said. Using Storyboards is indeed a pain in the ass for several reasons like merge conflicts and slow loading but switching entirely to code to create your views is like going to another extreme end of the spectrum. Instead, XIB's would have been a better solution. The interface is important as it allows new people joining your team easily visualize how the view looks. Also, copy pasting the code to the playground just to see what the view looks like is a bit of a tedious process. Don't get me wrong the article is great, for I didn't know you could do that with playground but that doesn't justify moving entirely to code.
Also i would like to point out that in case of overlapping views you can see all the views at a certain position by shift+right click
Just code. There is no need for storyboards in iOS. Do your self a favor and learn how to layout a view programmatically. It will save you time and nerves :)
If I understand correctly, if you want to revisit a view later, you have to copy it into playground again? Still sounds tedious.
Does this address one problem we've found with automated ui testing where views don't have useful ids? (xcode usually generates random ids for views which you can't control). Here I guess you could set your own.
In android, views are usually defined in xml in subcomponents as small as you like. You give each view you want to reference in code an id that you define. When writing a ui test, logically named ids are easy to reference.
Yes, you would have to copy-paste back and forth in most cases. I'm sure there's a workaround somewhere, although it's a small price to pay for the benefit that programatic views provide and not every solution is perfect. Both methods of creating views have their issues.
Addressing the automated UI-testing, I'm not sure on that. I'd assume you'd be able to set the IDs somehow.
I think the problem with providing proper id's to view can be solved by writing an extension over UIView and adding @IBInspectable property to UIView using associated type. Though it would work like a tag with string type instead of int. You can do that if it helps! :)
I encourage everyone to use storyboards first. It's not a fit-all solution, and sometimes you'll need to use a .xib or code, but storyboard should come first.
There's a bit of a learning curve - but heres the thing. If you build ALL your views & layouts in .xib or code... you're creating a maintainability disaster. First off, creating navigation in code is the biggest source of crashes in iOS. Secondly, (for example) when going through a branding change - I can change an entire app in an hour with a storyboard. Where, it could take a whole day to do it in code. And you're bound to miss something.
Good article Jordan - It's great to see young programmers in the community :) It's also great for people to know how these things work in code. Keep it up!
I definitely agree with this, trying storyboards before code is a good idea because then you have an opportunity to learn the ropes of the auto-layout system in an easier environment. Once you go from storyboards to code, it’s much easier than just going into code because then you generally understand how it all works.
Thanks for the Github link 😻
I had to wait 1 minute for Main.storyboard to open up on my Macbook Air. Great tutorial, one thing I hate is that translates thing we have to set to false, I always forget setting it :p
Tips for developers: DON'T USE Storyboard