Skip to content

Commit

Permalink
Merge pull request #992 from square/dhaval/viewRegistryDocs
Browse files Browse the repository at this point in the history
Update docs to reflect ViewRegistry removal:
  • Loading branch information
dhavalshreyas authored Mar 4, 2020
2 parents 485af5a + 3fdc927 commit 99ddffb
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 118 deletions.
4 changes: 2 additions & 2 deletions docs/tutorial/building-a-view-controller-from-screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class DemoScreenViewController: ScreenViewController<DemoScreen> {

private let button: UIButton

required init(screen: DemoScreen, viewRegistry: ViewRegistry) {
required init(screen: DemoScreen) {
button = UIButton()
super.init(screen: screen, viewRegistry: viewRegistry)
super.init(screen: screen)

update(screen: screen)
}
Expand Down
33 changes: 6 additions & 27 deletions docs/tutorial/using-a-workflow-for-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@ public final class ContainerViewController<Output, ScreenType>: UIViewController
/// Emits output events from the bound workflow.
public let output: Signal<Output, Never>

public convenience init<W: Workflow>(workflow: W, viewRegistry: ViewRegistry) where W.Rendering == ScreenType, W.Output == Output
public convenience init<W: Workflow>(workflow: W) where W.Rendering == ScreenType, W.Output == Output
}

```

The first initializer argument is the workflow that will drive your application.

The second initializer argument is the view registry. The view registry acts as a mapping between
the view models (`Screen`s) that your workflow emits and the concrete UI implementations that should
be used to display them.
The initializer argument is the workflow that will drive your application.

```swift
import UIKit
Expand All @@ -38,11 +34,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)

var viewRegistry = ViewRegistry()

let container = ContainerViewController(
workflow: DemoWorkflow(),
viewRegistry: viewRegistry)
workflow: DemoWorkflow()
)

window.rootViewController = container
self.window = window
Expand All @@ -53,21 +47,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

```

Your project should compile at this point. It will crash as soon as the workflow emits a screen,
however, because we have not registered any UI implementations with the view registry. Let's fix
that:

```swift
var viewRegistry = ViewRegistry()

// Register the DemoScreenViewController to be responsible for DemoScreen.
viewRegistry.register(screenViewControllerType: DemoScreenViewController.self)

let container = ContainerViewController(
workflow: DemoWorkflow(),
viewRegistry: viewRegistry)
```

Now, when the `ContainerViewController` is shown, it will start the workflow and `render` will be
called returning the `DemoScreen`. The container will use the view registry to map the `DemoScreen`
to a `DemoScreenViewController` and add it to the view hierarchy to display.
called returning the `DemoScreen`. The container will use `viewControllerDescription` to build
a `DemoScreenViewController` and add it to the view hierarchy to display.
24 changes: 10 additions & 14 deletions swift/Samples/Tutorial/Tutorial1.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ struct WelcomeScreen: Screen {
var onNameChanged: (String) -> Void
/// Callback when the login button is tapped.
var onLoginTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return WelcomeViewController.description(for: self)
}
}
```

Expand All @@ -54,9 +58,9 @@ import TutorialViews
final class WelcomeViewController: ScreenViewController<WelcomeScreen> {
var welcomeView: WelcomeView

required init(screen: WelcomeScreen, viewRegistry: ViewRegistry) {
required init(screen: WelcomeScreen) {
self.welcomeView = WelcomeView(frame: .zero)
super.init(screen: screen, viewRegistry: viewRegistry)
super.init(screen: screen)
update(with: screen)
}

Expand Down Expand Up @@ -122,24 +126,16 @@ public final class TutorialContainerViewController: UIViewController {
let containerViewController: UIViewController

public init() {
// Create a view registry. This will allow the infrastructure to map `Screen` types to their respective view controller type.
var viewRegistry = ViewRegistry()
// Register the `WelcomeScreen` and view controller with the convenience method the template provided.
viewRegistry.registerWelcomeScreen()

// Create a `ContainerViewController` with the `WelcomeWorkflow` as the root workflow, with the view registry we just created.
// Create a `ContainerViewController` with the `WelcomeWorkflow` as the root workflow.
containerViewController = ContainerViewController(
workflow: WelcomeWorkflow(),
viewRegistry: viewRegistry)
workflow: WelcomeWorkflow()
)

super.init(nibName: nil, bundle: nil)
}
```

We did a few things here.
- We created a *view registry* that is used to map screen types to view controllers. The view registry is used by the container to determine what view controller to instantiate the first time we see a screen.
- We registered our `WelcomeScreen` with the view registry so we have that mapping.
- We created our `ContainerViewController` with the `WelcomeWorkflow` as the root.
Now, we've created our `ContainerViewController` with the `WelcomeWorkflow` as the root.

We can finally run the app again! It will look the exact same as before, but now powered by our workflow.

Expand Down
52 changes: 19 additions & 33 deletions swift/Samples/Tutorial/Tutorial2.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,19 @@ struct TodoListScreen: Screen {

// It should also contain callbacks for any UI events, for example:
// var onButtonTapped: () -> Void

// It should also return viewControllerDescription property that
// describes the UIViewController that will be used for rendering
// the screen.
}


final class TodoListViewController: ScreenViewController<TodoListScreen> {
let todoListView: TodoListView

required init(screen: TodoListScreen, viewRegistry: ViewRegistry) {
required init(screen: TodoListScreen) {
self.todoListView = TodoListView(frame: .zero)
super.init(screen: screen, viewRegistry: viewRegistry)
super.init(screen: screen)
update(with: screen)
}

Expand Down Expand Up @@ -77,28 +81,21 @@ extension TodoListWorkflow {

### Showing the new screen and workflow

For now, let's just show this new screen instead of the login screen/workflow. Update the `TutorialContainerViewController` to register to the new screen and show the `TodoListWorkflow`:
For now, let's just show this new screen instead of the login screen/workflow. Update the `TutorialContainerViewController` to show the `TodoListWorkflow`:

```swift
public final class TutorialContainerViewController: UIViewController {
let containerViewController: UIViewController

public init() {
// Create a view registry. This will allow the infrastructure to map `Screen` types to their respective view controller type.
var viewRegistry = ViewRegistry()
// Register the `WelcomeScreen` and view controller with the convenience method the template provided.
viewRegistry.registerWelcomeScreen()
// Register the `TodoListScreen` and view controller with the convenience method the template provided.
viewRegistry.registerTodoListScreen()

// Create a `ContainerViewController` with the `WelcomeWorkflow` as the root workflow, with the view registry we just created.
// Create a `ContainerViewController` with the `WelcomeWorkflow` as the root workflow.
// containerViewController = ContainerViewController(
// workflow: WelcomeWorkflow(),
// viewRegistry: viewRegistry)
// workflow: WelcomeWorkflow()
// )
// Show the TodoList Workflow instead:
containerViewController = ContainerViewController(
workflow: TodoListWorkflow(),
viewRegistry: viewRegistry)
workflow: TodoListWorkflow()
)

super.init(nibName: nil, bundle: nil)
}
Expand Down Expand Up @@ -236,10 +233,10 @@ public final class TutorialContainerViewController: UIViewController {
public init() {
// ...

// Create a `ContainerViewController` with the `RootWorkflow` as the root workflow, with the view registry we just created.
// Create a `ContainerViewController` with the `RootWorkflow` as the root workflow.
containerViewController = ContainerViewController(
workflow: RootWorkflow(),
viewRegistry: viewRegistry)
workflow: RootWorkflow()
)

super.init(nibName: nil, bundle: nil)
}
Expand Down Expand Up @@ -474,7 +471,7 @@ This works, but with no animation between the two screens it's pretty unsatisfyi

### Back Stack and "Containers"

We want to put our different screens in a navigation controller. Because we want all of our navigation state to be declarative, we need to use the `BackStackContainer` to do this - by registering and using the `BackStackScreen`:
We want to put our different screens in a navigation controller. Because we want all of our navigation state to be declarative, we need to use the `BackStackContainer` to do this - by using the `BackStackScreen`:

```swift
public struct BackStackScreen: Screen {
Expand All @@ -488,8 +485,6 @@ public struct BackStackScreen: Screen {

The `BackStackScreen` contains a list of all screens in the back stack that are specified on each render pass.

Register the `BackStackScreen` so that we can use it in the TutorialContainerViewController:

```swift
import UIKit
import Workflow
Expand All @@ -501,19 +496,10 @@ public final class TutorialContainerViewController: UIViewController {
let containerViewController: UIViewController

public init() {
// Create a view registry. This will allow the infrastructure to map `Screen` types to their respective view controller type.
var viewRegistry = ViewRegistry()
// Register the `WelcomeScreen` and view controller with the convenience method the template provided.
viewRegistry.registerWelcomeScreen()
// Register the `TodoListScreen` and view controller with the convenience method the template provided.
viewRegistry.registerTodoListScreen()
// Register the `BackStackContainer`, which provides a container for the `BackStackScreen`.
viewRegistry.registerBackStackContainer()

// Create a `ContainerViewController` with the `RootWorkflow` as the root workflow, with the view registry we just created.
// Create a `ContainerViewController` with the `RootWorkflow` as the root workflow.
containerViewController = ContainerViewController(
workflow: RootWorkflow(),
viewRegistry: viewRegistry)
workflow: RootWorkflow()
)

super.init(nibName: nil, bundle: nil)
}
Expand Down
43 changes: 12 additions & 31 deletions swift/Samples/Tutorial/Tutorial3.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ final class TodoEditViewController: ScreenViewController<TodoEditScreen> {
// The `todoEditView` has all the logic for displaying the todo and editing.
let todoEditView: TodoEditView

required init(screen: TodoEditScreen, viewRegistry: ViewRegistry) {
required init(screen: TodoEditScreen) {
self.todoEditView = TodoEditView(frame: .zero)

super.init(screen: screen, viewRegistry: viewRegistry)
super.init(screen: screen)
update(with: screen)
}

Expand Down Expand Up @@ -85,6 +85,16 @@ struct TodoEditScreen: Screen {
}
```

The `Screen` protocol also requires a `viewControllerDescription` property. This describes the `UIViewController` that will be used to render the screen:

```swift
extension TodoEditScreen {
var viewControllerDescription: ViewControllerDescription {
TodoEditViewController.description(for: self)
}
}
```

Then update the view with the data from the screen:

```swift
Expand All @@ -106,35 +116,6 @@ final class TodoEditViewController: ScreenViewController<TodoEditScreen> {
}
```

Finally, register the `TodoEditScreen` in the `TutorialContainerViewController` with the viewRegistry:

```swift
public final class TutorialContainerViewController: UIViewController {
let containerViewController: UIViewController

public init() {
// Create a view registry. This will allow the infrastructure to map `Screen` types to their respective view controller type.
var viewRegistry = ViewRegistry()
// Register the `WelcomeScreen` and view controller with the convenience method the template provided.
viewRegistry.registerWelcomeScreen()
// Register the `TodoListScreen` and view controller with the convenience method the template provided.
viewRegistry.registerTodoListScreen()
// Register the `BackStackContainer`, which provides a container for the `BackStackScreen`.
viewRegistry.registerBackStackContainer()
// Register the `TodoEditScreen` and view controller with the convenience method the template provided.
viewRegistry.registerTodoEditScreen()

// Create a `ContainerViewController` with the `RootWorkflow` as the root workflow, with the view registry we just created.
containerViewController = ContainerViewController(
workflow: RootWorkflow(),
viewRegistry: viewRegistry)

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

// ... rest of the implementation ...
```

#### TodoEditWorkflow

Now that we have our screen and view controller, update the `TodoEditWorkflow` to emit this screen as the rendering.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ struct ___VARIABLE_productName___Screen: Screen {

// It should also contain callbacks for any UI events, for example:
// var onButtonTapped: () -> Void

var viewControllerDescription: ViewControllerDescription {
return ___VARIABLE_productName___ViewController.description(for: self)
}
}


final class ___VARIABLE_productName___ViewController: ScreenViewController<___VARIABLE_productName___Screen> {

required init(screen: ___VARIABLE_productName___Screen, viewRegistry: ViewRegistry) {
super.init(screen: screen, viewRegistry: viewRegistry)
required init(screen: ___VARIABLE_productName___Screen) {
super.init(screen: screen)
update(with: screen)
}

Expand All @@ -28,12 +32,3 @@ final class ___VARIABLE_productName___ViewController: ScreenViewController<___VA
}

}


extension ViewRegistry {

public mutating func register___VARIABLE_productName___Screen() {
self.register(screenViewControllerType: ___VARIABLE_productName___ViewController.self)
}

}

0 comments on commit 99ddffb

Please sign in to comment.