Screen
public protocol Screen : CustomStringConvertible
A protocol for a factory that builds a screen module and returns its container.
This protocol provides a universal interface for building a screen module, independent of its architectural pattern: MVC, VIPER, MVVM, etc.
Since the factory is the external entry point to the screen,
the factory is called the Screen
for convenience.
External Parameters
Most screens require some external parameters for their configuration. All such parameters should be declared as properties of the implementation of this protocol.
For example, a chat screen requires a chat ID:
class ChatViewController: UIViewController {
let chatID: Int
init(chatID: Int) {
self.chatID = chatID
super.init(nibName: nil, bundle: nil)
}
}
Then the implementation of its factory might look like this:
struct ChatScreen: Screen {
let chatID: Int
func build(navigator: ScreenNavigator) -> UIViewController {
ChatViewController(chatID: chatID)
}
}
To create this chat screen, you will need to pass the ID to the initializer:
let chatScreen = ChatScreen(chatID: 123)
navigator.navigate(fromTop: .stack) { route in
route.push(chatScreen)
}
Screen Key
Each screen has the name
and traits
properties, which are used to create a screen key.
You can use this key to create a container that can be found in the hierarchy.
Just conform your view controller to the ScreenKeyedContainer
protocol and initialize it with this key.
See the ScreenKeyedContainer
protocol for an example of this approach.
Default implementation of the name
property returns type name:
let chatScreen = ChatScreen(chatID: 123)
print(chatScreen.name) // Prints: "ChatScreen"
Usually you don’t need to implement the name
property yourself.
If you want to distinguish between screens of the same type, implement the traits
property.
For example, chat screens may be different if they have different chat IDs.
In this case, the traits
property must include the chat ID:
struct ChatScreen: Screen {
let chatID: Int
var traits: Set<AnyHashable> {
[chatID]
}
func build(navigator: ScreenNavigator) -> UIViewController {
ChatViewController(chatID: chatID)
}
}
Then the keys for 2 screens with different chat ID will not be equal:
let firstScreen = ChatScreen(chatID: 1)
let secondScreen = ChatScreen(chatID: 2)
print(firstScreen.key == secondScreen.key) // Prints: "false"
Simple Screens
If your screen consists only of a view controller, implementing a factory can be an extra complication.
In this case, you can conform your view controller to the Screen
protocol:
class SimpleViewController: UIViewController, Screen { }
The default implementation will return self
in the build(navigator:)
method,
and an instance of this controller can be used as a factory in navigation:
navigator.navigate(fromTop: .stack) { route in
route.push(SimpleViewController())
}
See also
ScreenKey
See also
ScreenContainer
See also
AnyScreen
-
A type of container that the screen uses for navigation.
See also
ScreenContainer
Declaration
Swift
associatedtype Container : ScreenContainer
-
name
Default implementationScreen name.
Default implementation returns type name.
Default Implementation
Declaration
Swift
var name: String { get }
-
traits
Default implementationScreen traits that are used to distinguish screens with the same name.
Default implementation returns empty set.
Default Implementation
Declaration
Swift
var traits: Set<AnyHashable> { get }
-
Builds the screen module and returns its container.
Declaration
Swift
func build(navigator: ScreenNavigator) -> Container
Parameters
navigator
The navigator instance that the screen should use for its own navigation.
Return Value
Container instance.
-
eraseToAnyScreen()
Extension methodWraps this screen with a type eraser.
Use
eraseToAnyScreen()
to expose an instance ofAnyScreen
, rather than this screen’s actual type. This form of type erasure preserves abstraction across API boundaries, such as different modules. When you expose your screens as theAnyScreen
type, you can change the underlying implementation over time without affecting existing clients.See also
Return Value
An
AnyScreen
wrapping this screen. -
decorated(by:
Extension method) Undocumented
Declaration
Swift
public func decorated<Decorator: ScreenDecorator>( by decorator: Decorator ) -> AnyScreen<Decorator.Output> where Container == Decorator.Container
-
description
Extension methodDeclaration
Swift
public var description: String { get }
-
key
Extension methodScreen key that can be used to search for a container in the container hierarchy.
This key can be used to create a container of the
ScreenKeyedContainer
type. Default implementation creates key using the values of thename
andkey
properties.See also
ScreenKeyedContainer
Declaration
Swift
public var key: ScreenKey { get }
-
eraseToAnyModalScreen()
Extension methodWraps this screen with a type eraser.
Use
eraseToAnyModalScreen()
to expose an instance ofAnyModalScreen
, rather than this screen’s actual type. This form of type erasure preserves abstraction across API boundaries, such as different modules. When you expose your screens as theAnyModalScreen
type, you can change the underlying implementation over time without affecting existing clients.See also
See also
Declaration
Swift
public func eraseToAnyModalScreen() -> AnyModalScreen
Return Value
An
AnyModalScreen
wrapping this screen.
-
eraseToAnyStackScreen()
Extension methodWraps this screen with a type eraser.
Use
eraseToAnyStackScreen()
to expose an instance ofAnyStackScreen
, rather than this screen’s actual type. This form of type erasure preserves abstraction across API boundaries, such as different modules. When you expose your screens as theAnyStackScreen
type, you can change the underlying implementation over time without affecting existing clients.See also
See also
Declaration
Swift
public func eraseToAnyStackScreen() -> AnyStackScreen
Return Value
An
AnyStackScreen
wrapping this screen.
-
eraseToAnyTabsScreen()
Extension methodWraps this screen with a type eraser.
Use
eraseToAnyTabsScreen()
to expose an instance ofAnyTabsScreen
, rather than this screen’s actual type. This form of type erasure preserves abstraction across API boundaries, such as different modules. When you expose your screens as theAnyTabsScreen
type, you can change the underlying implementation over time without affecting existing clients.See also
See also
Declaration
Swift
public func eraseToAnyTabsScreen() -> AnyTabsScreen
Return Value
An
AnyTabsScreen
wrapping this screen.
-
withModalStyle(_:
Extension method) Undocumented
Declaration
Swift
public func withModalStyle(_ style: ScreenModalStyle) -> AnyScreen<Container>
-
withModalPresentationStyle(_:
Extension method) -
withModalTransitionStyle(_:
Extension method) -
withModalTransitioningDelegate(_:
Extension method) -
withPopoverPresentation(anchor:
Extension method) Undocumented
Declaration
Swift
public func withPopoverPresentation(anchor: ScreenPopoverPresentationAnchor) -> AnyScreen<Container>
-
withLeftBarButton(_:
Extension method) -
withRightBarButton(_:
Extension method) -
withStackContainer(of:
Extension method) Undocumented
Declaration
Swift
public func withStackContainer<Output: UINavigationController>( of type: Output.Type ) -> AnyScreen<Output>
-
withStackContainer()
Extension methodUndocumented
Declaration
Swift
public func withStackContainer() -> AnyStackScreen
-
withTabBarItem(_:
Extension method)
-
withStack(_:
Extension method) Undocumented
Declaration
Swift
public func withStack(_ stack: [AnyModalScreen]) -> AnyScreen<Container>
-
withStack(_:
Extension method) Undocumented
Declaration
Swift
public func withStack(_ stack: AnyModalScreen...) -> AnyScreen<Container>
-
withStack(_:
Extension method) -
withStack(_:
Extension method_: ) -
withStack(_:
Extension method_: _: ) -
withStack(_:
Extension method_: _: _: ) Undocumented
Declaration
-
withStack(_:
Extension method_: _: _: _: ) Undocumented
Declaration
Swift
public func withStack<T0: Screen, T1: Screen, T2: Screen, T3: Screen, T4: Screen>( _ screen0: T0, _ screen1: T1, _ screen2: T2, _ screen3: T3, _ screen4: T4 ) -> AnyScreen<Container> where T0.Container: UIViewController, T1.Container: UIViewController, T2.Container: UIViewController, T3.Container: UIViewController, T4.Container: UIViewController
-
withTabs(_:
Extension method) Undocumented
Declaration
Swift
public func withTabs(_ tabs: [AnyModalScreen]) -> AnyScreen<Container>
-
withTabs(_:
Extension method) Undocumented
Declaration
Swift
public func withTabs(_ tabs: AnyModalScreen...) -> AnyScreen<Container>
-
withTabs(_:
Extension method) -
withTabs(_:
Extension method_: ) -
withTabs(_:
Extension method_: _: ) -
withTabs(_:
Extension method_: _: _: ) Undocumented
Declaration
-
withTabs(_:
Extension method_: _: _: _: ) Undocumented
Declaration
Swift
public func withTabs<T0: Screen, T1: Screen, T2: Screen, T3: Screen, T4: Screen>( _ screen0: T0, _ screen1: T1, _ screen2: T2, _ screen3: T3, _ screen4: T4 ) -> AnyScreen<Container> where T0.Container: UIViewController, T1.Container: UIViewController, T2.Container: UIViewController, T3.Container: UIViewController, T4.Container: UIViewController