How to prevent ViewController initiation unexpected behavior

Kittisak Phetrungnapha
iTopStory
Published in
4 min readApr 6, 2018

--

For iOS developers nowadays, there are many ways to create ViewController. How do you create it? By Storyboard, Xib file, or Programmatically?

// Storyboard
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! ViewController
// By Xib or Programmatically
let vc = ViewController()

Mostly, you have to pass some parameters from current view controller to a new one that you just created. Right? Assume that your view controller always need one parameter “username” and you are sure that it has never been nil so you declare something like this

class ViewController: UIViewController {    var username: String!

...
}

Then before you navigate to that view controller you assign username and present it.

// Storyboard
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! ViewController
// By Xib or Programmatically
let vc = ViewController()
vc.username = "iTopStory" // assign parameter
present(vc, animated: true)

It looks straightforward, easy, and fine if you are solo project. But in the real world you have to work with your colleagues. More than one people for a single project. Imagine your project does not have unit test. Someday your colleagues (or even you) would like to change or refactor that code. Your colleagues (again, or even you because this code has been written for a long time and you cannot remember everything that you wrote) are unintended to remove this line

vc.username = "iTopStory"

Yeah, you know what will happen next if you run this code and access username again. Apps will crash due to found nil while unwrapping optional value. Boom! So, it’s better if you have a way to let compiler knows this will be a problem and does not allow to compile successfully. Shows compile error which file and line are lead to the problem.

Factory pattern and private init come to rescue

https://www.tutorialspoint.com/design_pattern/factory_pattern.htm

The above picture is the mechanism how Factory pattern works. You may think like this

“I just want to create a new simple view controller so why I need to use something that looks complicated. Hmm”

Yeah, I agree with you but keep calm and take it easy. We will just use a half of Factory pattern bypass by just create static function that initiation view controller, assign their needed parameters, then return it. Last but not least, do not forget to make private init() of your view controller. That’s it.

Create by Storyboard:

class ViewController: UIViewController {    private var username: String!

static func createInstance(username: String) -> ViewController {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! ViewController
vc.username = username
return vc
}

private init() {
super.init(nibName: nil, bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
...

}
// Caller
let vc = ViewController.createInstance(username: "iTopStory")

Create Xib file or programmatically

class ViewController: UIViewController {    private let username: String

static func createInstance(username: String) -> ViewController {
return ViewController(username: username)
}

private init(username: String) {
self.username = username
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
...}// Caller
let vc = ViewController.createInstance(username: "iTopStory")

So, the problem that I told you above will be gone because you force your colleagues and even yourself to create a new view controller by using static function. No way to create like this

let vc = ViewController(username: "iTopStory") // Compile error due to we add private to init function.

So, we will never forget to assign “username” to our ViewController or delete this line anymore!

Result

If you are creating a view controller by xib file (like me). You can use let instead of var for declaration username. It’s immutable, thread safe, high performance. You can keep your variable as private. You follow DRY because of you always have to use only one function for creating a view controller.

However, you should not use segue if you are using storyboard because it will break rules. It’s your choice to choose which one is fit with your requirements.

Call to Action

Thanks for your time to read this article. I hope it will be useful for some iOS developer guy in the world. If you have any question, feel free to comment below or say hello in Twitter @itopstack. I like to share knowledge that I know in both Thai and English. See you again next time.

--

--

Kittisak Phetrungnapha
iTopStory

I am a software engineer who fall in love to code, read, and write. :) itopstory.com