Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docs to reflect ViewRegistry removal: #992

Merged
merged 1 commit into from
Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's ___VARIABLE_productName___ViewController?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for the Xcode templates

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool!

}
}


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)
}

}