One of the projects that I’ve been working on, probably the one that is the most applicable for iOS development in a vacuum, is called fuikit (functional UIKit). Fuikit is comprised of subclasses of all the major UIKit classes (UIViewController, UITableViewController, UITableViewDelegate, CLLocationManagerDelegate, etc.), but abstracting all of the superclass’ methods into optional, settable functions. As a dumbed-down example, take FUIViewController:
public class FUIViewController: UIViewController {
public var onViewDidLoad: ((FUIViewController) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
onViewDidLoad?(self)
}
}
I’ve only written out viewDidLoad, but you can imagine filling all of the inherited methods in a similar way, each settable function variable taking an FUIViewController as a parameter in addition to ones the inherited functions take (onViewDidAppear, for example, is ((FUIViewController, Bool) -> Void)?).
This is one of the building blocks of the way that I’ve learned to develop mobile apps, and if you were to peruse the projects that I work on every day, you’d see the same paradigm popping up in a ton of files:
func viewController(styleVC: @escaping (ViewController) -> Void, ...other parameters) -> ViewController {
//initialize vc
vc.onViewDidLoad = ~>styleVC // ~> prefix operator optionally casts the
FUIViewController into a ViewController and then
runs styleVC if the cast is successful
//configure vc in other ways
return vc
}
class ViewController: FUIViewController {
// outlets
// vars
override func viewDidLoad() {
super.viewDidLoad() // this will call styleVC
// other stuff that you want to happen
}
}
It forces you to be much more deliberate in when and how you want certain things to happen in the ViewController’s lifecycle. This way, you will never get a pesky crash from referencing an outlet before it’s been instantiated, because the interface you’re using to interact with your ViewController guarantees that. We generally always pass a styleVC parameter to handle tweaking the UI, and have a configure function that helps to populate the ViewController with data, whether that be through a network or just static data.
One of the advantages to the design of this library is that it’s completely airtight — anywhere you want to use a UIViewController, you can use a FUIViewController. The same applies with all the other superclasses. It also encourages the user to split up your styling, computation, and population, all while discouraging the user from the Massive View Controller. Writing a complicated View Controller is much harder when it gets to be hundred of lines long, and writing a complicated View Controller and then looking at your code and seeing the actual View Controller is only 8 lines long is also surprisingly rewarding.
One thought on “Deep Dive: fuikit”