Modular View Controller Hierarchies
-
Upload
rene-cacheaux -
Category
Technology
-
view
162 -
download
5
Transcript of Modular View Controller Hierarchies
Not Your Granddaddy's Architecture
Building Modularity into View Controller Hierarchies
The following takes place in an alternate reality
Meet Jax
Jax is a super awesome app developer
or at least, he thinks he is
Jax pounds red bulls and talks about how sick his
coding skills are.
Most importantly, he loves watermelon
Jax just got hired working on the next world changing app.
My Pet Alien
My Pet Alien is an app that tracks your pet alien's health,
and will alert you if your alien
is getting sick.
"Sure, that will take 2 months, EASY.” - Jax
Jax spends the next 2 months pounding red bulls, building flows in Interface builder, and coding the entire app.
(we’re going to jump into Jax’s train of thought as
he builds this out)
Jax thinks back to 2009…
Jax fell in love with iOS at WWDC
That’s where Jax learned how to build navigation flows.
He even got to see Scott on stage
If you’re asking who Scott is…
Jax looks at the designs…
“Apps are made of view controller hierarchies”
“Ok, I need a nav controller and three
content view controllers”
Jax begins sketching this out
Container View Controller
Content View Controller
Navigation Controller, Tab Controller, Page View Controller, Split View Controller, custom
Table View Controller, Collection View Controller, custom
View Controller Hierarchy
Home View Controller
Table View Controller
Detail View Controller
WindowNavigation Controller
Root View Controller
Jax opens up a storyboard and starts building.
Lets review how this works
View Controller Hierarchy
Home View Controller
Table View Controller
Detail View Controller
WindowNavigation Controller
Root View Controller
View Controller Hierarchy
Home View Controller
Table View Controller
Detail View Controller
Navigation Controller
View Controller Hierarchy
On App Launch…
On App Launch…Storyboard
On App Launch…Storyboard
Storyboard
On User Interaction…Creates Table View Controller
Storyboard
On User Interaction…Creates Table View Controller
Storyboard
On User Interaction…Calls Prepare for Segue
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Storyboard
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Storyboard
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Storyboard
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Storyboard
Storyboard Pushes View Controller onto Stack
On User Interaction…
Storyboard
On Cell Selection…
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Store Selected ID
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Store Selected ID
Perform Segue
Storyboard Creates Detail View Controller
On Cell Selection…
Storyboard Creates Detail View Controller
On Cell Selection…
Storyboard Calls Prepare for Segue
On Cell Selection…
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Storyboard Pushes View Controller onto Stack
On Cell Selection…
2 months later, Jax is done!
Success!
Jax looks at iTunes Connect
The downloads are pouring in.
The investors are interested.
Funded!
Turns out there’s a lot of alien pet owners out there!
With all the new $ and feature requests, the
company decides to hire another engineer.
Meet Jiles
Jiles is an application developer from Great Britain. A seasoned
professional.
Jiles and Jax meet.
Jiles congratulates Jax on his success.
Jiles asks Jax what he thinks of the application
architecture he has designed.
Jax says its the best, everything is
perfect.
Jax tells the company he’s taking a month long vacation to Thailand.
Peace!
Jiles feels good about his new position and (seemingly) solid
codebase.
The next day…
The project manager asks Jiles to include the pet list screen before the
login screen.
and to place a new detail screen between the pet list and pet detail.
Jiles thinks to himself, ya know, Jax said the architecture was solid, this should take me
about 30 minutes.
Jax starts working on moving the list and detail screens.
Easy!
Easy!
Easy!
Easy!
Easy!
Easy!
So he thought…
!?
EMPTY!
What’s going on here?
Let’s review how Jax built this…
On User Interaction…
Storyboard
On User Interaction…Creates Table View Controller
Storyboard
On User Interaction…Creates Table View Controller
Storyboard
On User Interaction…Calls Prepare for Segue
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Storyboard
On User Interaction…HomeViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Storyboard
Home VC fetches Table VC’s data
Isolate content view controllers!
Content controllers should know how to retrieve their own data
!?
EMPTY!
!?COUPLED CONTENT
View controllers!
It’s now 2 am…
After an hour of re-wiring, Jax moves on to adding the new screen.
“Well at least this one will be easy!”
Easy!
Easy!
So he thought…
What’s going on here?
Let’s review how Jax built this…
On Cell Selection…
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Store Selected ID
Storyboard
On Cell Selection…TableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
Store Selected ID
Perform Segue
Storyboard Creates New View Controller
On Cell Selection…
Storyboard Creates New View Controller
On Cell Selection…
Storyboard Calls Prepare for Segue
On Cell Selection…
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Storyboard
On Cell Selection…TableViewController.swiftoverride func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
Match Segue string
Cast new VC
Set up new VC
Table VC doesn’t know NewVC
Table VC only knows DetailVC
COUPLED CONTENT View controllers!
Isolate content view controllers
What are we losing?
• Ability to
• re-order content view controllers
• reuse content view controllers
Next day…
Jiles comes in looking like he was hit by a
train and mauled by some cats.
Jiles delivers, but is exhausted
Jiles thinks...
he should be able to move this list anywhere in the app, and it should just
work!
Jiles thinks...
View controllers should be able to live on their own. They should not depend on the container they are in
and they should not depend on sibling
content controllers.
Sometime in the Future...
Jiles goes to WWDC in search of a better view controller architecture
Jiles meets John in line for the
keynote
John asks, “how’s it going, how
was your last project?”
Jiles explains the problems he faced,
he tells John, “there must be a better way!”
John has experienced the exact same
problems as Jiles
John says, "I've found a better way"
Jiles is happy... and eager to learn more!
John starts explaining…
So where should logic go?
So where should logic go?Can’t go here
So where should logic go?Can’t go here
So where should logic go?Can’t go here
So where?
So where should logic go?
Navigation View Controller
So where should logic go?Navigation View Controller
So where should logic go?Navigation View Controller why not here?
So where should logic go?
UINavigationController IS
a container view controller
Subclassing isn’t always
evil
How would this work?
Content View Controllers
Think of as async task
Inputs and Outcomes
Inputs and Outcomes
After init, provide input
Inputs and Outcomes
When finished, report outcome
Input
• Either
• initializer arguments
• public variable properties
Outcome
• Either
• onComplete closure (selectedId: String)->()
• leverage targetViewControllerForAction
class TableViewController: UITableViewController { // Input var userId: String? // Outcome var onComplete: ((selectedId: String)->())? }
Input-Outcome Based VC
// Inside Container View Controller...
let tableVC = TableViewController(style: .Plain) tableVC.userId = loggedInUserId tableVC.onComplete = { selectedId in // Container VC decides where to go next }
Container’s Usage
Back to our navigation controller…
On App Launch
Creates HomeVCMyNavigationController.swiftlet homeVC = HomeVC()
Creates HomeVCMyNavigationController.swiftlet homeVC = HomeVC()
Pushes HomeVCMyNavigationController.swiftpushViewController(homeVC, animated: false))
On User Interaction… HomeViewController.swiftonComplete()
On User Interaction… MyNavigationController.swiftlet tableVC = TableViewController()
Nav controller manages content view controllers
On User Interaction… MyNavigationController.swiftlet tableVC = TableViewController()
Nav controller manages content view controllers
On User Interaction… MyNavigationController.swiftpushViewController(tableVC, animated: true)
On Cell SelectionTableViewController.swiftfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
On Cell SelectionTableViewController.swiftonComplete(selectedId: viewModelObject.id)
On Cell SelectionMyNavigationController.swiftlet detailVC = DetailViewController(modelId: selectedId)
On Cell SelectionMyNavigationController.swiftlet detailVC = DetailViewController(modelId: selectedId)
On Cell SelectionMyNavigationController.swiftlet detailVC = DetailViewController(modelId: selectedId)
On Cell SelectionMyNavigationController.swiftpushViewController(detailVC, animated: true)
Demo!
Composition
Remember
Dependencies
Content View Controllers should not depend on
• a specific container view controller class
• sibling content view controllers
Think of view controllers as lego blocks
If you liked this, there’s more
Elements
Josh BerlinCollection View [email protected]
@jab2109
René CacheauxiOS [email protected]
[email protected]@RCachATX