thoughtbot / Perform

Easy dependency injection for storyboard segues
MIT License
280 stars 12 forks source link

Searching for a view controller of the matching type is useful outside of segues #6

Closed sharplet closed 8 years ago

sharplet commented 8 years ago

It would be nice to expose the functionality of UIStoryboardSegue.destinationViewController(ofType:) in a more general way that is useful in different contexts.

For example, lets say you wanted to configure the tabs in a UITabBarController:

final class MyTabBarController: UITabBarController {
  override func viewDidLoad() {
    super.viewDidLoad()

    nextTab: for tab in viewControllers {
      for child in tab.hierarchy {
        switch child {
        case let feed as FeedViewController:
          // configure feed
          continue nextTab
        case let profile as ProfileViewController:
          // configure profile
          continue nextTab
        }
      } 
    }
  }
}

For each tab, this code searches the view controller hierarchy until it finds a matching view controller, then continues to the next tab.

This would be more concise:

for tab in viewControllers {
  if let feed = tab.childViewController(ofType: FeedViewController.self) {
    // configure feed
  }

  if let profile = tab.childViewController(ofType: ProfileViewController) {
    // configure profile
  }
}

But has the disadvantage of searching each tab N times, where N is the number of different things you need to configure.

I think there should be a way to encapsulate the first search strategy using a higher-level construct.

sharplet commented 8 years ago

I think something like this could work:

func viewDidLoad() {
  super.viewDidLoad()

  controller.configureTabs { child in
    switch child {
    case let feed as Feed:
      // configure feed
      return .configured

    case let profile as Profile:
      // configure profile
      return .configured

    default:
      return .ignored
    }

    // or...

    if let feed = child as? Feed {
      // configure feed
      return .configured
    }

    if let profile = child as? Profile {
      // configure profile
      return .configured
    }

    return .ignored
  }
}