ScenePivot: Complete Abstraction of View Controller Transition

Simon
3 min readDec 5, 2020

--

한국어를 찾으세요? 여기를 누르세요

ScenePivot pattern allows you to get rid of long and complicated UIViewController creation, configuration, presentation and dismissal from your UIViewController subclass implementation by abstracting the details behind a data type, SceneRequest and ScenePivot.

Creating, Configuring, Presenting and Dismissing a UIViewController

Let’s take a look at a code snippet from the famous sample code: Browsing and Modifying Photo Albums before refactoring it with ScenePivot.

addAlbum(_:) basically does the following two things:

  • Create and present UIAlertController with a Text Field
  • Creates a new Album with the entered text as title by calling PHPhotoLibrary.performChanges()

And let’s see how we can abstract the UIAlertController part.

ScenePivot and TextInputRequest

By planting a ScenePivot to MasterViewController and passing a TextInputRequest to ScenePivot we can drastically simplify addAlbum(_:) like below.

ViewControllerScenePivot is a concrete type conforms ScenePivot and passing self as UIViewController allows it to invoke present(:animted:completion:) to make actual presentation happen

pivot = ViewControllerScenePivot(viewController: self)

Creating TextInputRequest with a completion handler and sending it to ScenPivot is all it takes to present UIAlertController and take entered title.

let request = TextInputRequest(.newAlbum) {...}
pivot.switchScene(with: request)

Album creation part has been extracted to createNewAlbum(title:).

With ScenePivot and SceneRequest in place,

  • The presenting View Controller does not need to know the details of how the new View Controller is created and presented
  • It is hidden behind ScenePivot and SceneRequest
  • SceneRequest is only simple data structure represents dependencies and values the new Scene, based on UIViewController, requires
  • By hiding and abstracting the details, we can focus on implementing and debugging the View Controller’s own role: Rendering and Layout

By applying this pattern, we’ve experienced identifying more than another 20 View Controller transition take place and thousands of lines of code has been relocated or deleted.

Let’s take a short review on example implementation of ScenePivot before checking out what needs to be implemented behind TextInputRequest.

Example Implementation of ScenePivot API

Here is a simplified version of ScenePivot for demo purpose. The actual version used in the project I’m working on has more types and interfaces but has still not much of code. That’s because most of work is done by implementation that conforms ViewControllerScene.

A client simply create and send a SceneRequest to ScenePivot for transitioning to the next Scene. UIViewController subclasses or associated logic controllers are typical examples of clients.

ScenePivot asks SceneBuilder to create a ViewControllerScene from SceneRequest. That part is not included in the code snippet above, and ScenePivot asks SceneRequest to directly create ViewControllerScene for simplicity of demo.

Finally, the created Scene is asked to perform the actual presentation.

scene.present(from: viewController)

Back State: Behind TextInputRequest

Let’s take a look what needs to be done more in order for the code above to run.

struct TextInputRequest: SceneRequest is only a simple data type without any functionality. ViewControllerScene is responsible for presenting a scene and created by ViewControllerScceneBuildable from SceneRequest.

Hence, ViewControllerScene implements present(from:) that creates and presents UIAlertController.

Pushing to UINavigationController is also possible in addition to UIViewController.present(:animted:completion:). UIStoryboardSegue based transition can also be implemented with some limitation. Let’s hope for another chance to talk about it.

About TextInput(.newAlbum)

By adding TextInputRequest.InputType.newAlbum, we could simplify creation even further: TextInputRequest(.newAlbum).

It was possible because NSLocalizedString() parts have been separated from UIAlertController construction.

Summary

  • Transitioning to another UIViewController can be far more complicated than we think
  • How many possible different UIViewController transitions from a View Controller are there in the project you are working on?
  • SceneRequest represents dependencies and data for the next Scene
  • Scene transition is expressed as sending a SceneRequest to ScenePivot
  • It’s ViewControllerScene’s responsibility to create and present UIViewController and it takes SceneRequest and UIViewController as input
  • ScenePivot is rather a pattern than a framework. You may end up adopting it with a much improved version of implementation.

--

--