Stateful view controller containment for iOS and tvOS

Overview

Build

StateViewController

When creating rich view controllers, a single view controller class is often tasked with managing the appearance of many other views, controls, and other user interface elements based on a state. That state, in turn, is often derived from multiple sources that need to be synchronized to correctly represent a single reliable state. Usually the end result is known as the Massive View Controller problem, often solved by attempts to abandon the MVC pattern, the primary design pattern in UIKit. While other patterns, such as MVVM or MVP, can solve some issues, going with the grain rather than against makes interacting with UIKit more accommodating.

This repository houses a UIViewController subclass, enabling modularization and decoupling of view controllers, reducing the size of individual view controllers substantially, without the need for abandoning MVC as a design pattern.

Requirements

  • iOS 8.0+
  • tvOS 9.0+

Overview

StateViewController is a container view controller that presents one or more view controllers for any given state that you define, such as loading, list, or editing. It manages the appearance cycles of each child view controller, making sure that the view life cycle of the child view controllers are intact and in order, notifying you about state transitions and which child view controllers are about to appear or disappear from the view hierarchy. This allows you to compose multiple view controllers and re-use them throughout the app. The state view controller also provides extensive support for animating the transition between states.

Which view controller(s) are visible on screen is dictated by children(for:).

State transitions during appearance transition

When presented on screen, the a state view controller requires an initial state as a starting point. During its appearance transition, the loadAppearanceState() method is invoked to query the state appropriate to transition to as the state view controller appears on screen. If the appearance transition is animated, the state transition animation is respected, and target child view controllers have the option to appear asynchronously. If the appearance transition is not animated, all child view controllers are immediately placed on screen.

loadAppearanceState() must execute synchronously, and is a good place to query any persistence layer for available data, determining whether a final state is ready.

During appearance cycle

State transitions while on screen

When on-screen, invoking setNeedsTransition:to: will trigger a transition from the current state to the target state. A common practice is to have the transition from one state to another to trigger an an asynchronous operation (such as a network call), which upon completion, requests a third state based on the success of the asynchronous operation.

Between appearance cycle

Documentation

The source code documentation can be found here.

Installation

This module is available via Carthage. Modify your Cartfile to include StateViewController:

github "davidask/StateViewController"

Usage

import StateViewController

Subclassing StateViewController

To use StateViewController you must override it. The class specifies a generic with a subtype of State. The state type can be designed to house the actual model data required by your view controller, but that's an optional design decision. For instance, you can create a state that simply determines an abstract state:

enum MyState {
    case loading
    case ready
    case error
}

Or, you can define a state which in itself contains model data:

enum MyState {
    case loading
    case ready(MyModel)
    case error(Error)
}

Once you have a state, create a subclass of StateViewController.

class MyStateViewController: StateViewController<MyState>

Each time StateViewController is about to appear on screen it will call its loadAppearanceState() method. This method returns a state which should be ready for display as soon as the view controller is on screen. Override this method to determine what state is appropriate to display immediately, depending on cached data or the contents of your database.

override func loadAppearanceState() -> MyState {
    if let myModel = MyCache.cachedModel {
        return .ready(myModel)
    } else {
        return .loading
    }
}

Each state can be represented by zero or more view controllers. To provide which view controllers are visible for what state, override children(for:).

override func children(for state: MyState) -> [UIViewController] {
    switch state {
        case .loading:
            return [ActivityIndicatorViewController()]
        case .ready:
            return [myTableViewController]
        case .error:
            return [ErrorViewController()]
    }
}

You receive callbacks for when a state transition will begin, and when it has finished. willTransition(to:animated:) is a good place to prepare your child view controllers for appearance.

override func willTransition(to nextState: MyState, animated: Bool) {
    switch nextState {
        case .ready(let model):
            navigationItem.setRightBarButton(myBarButtonItem, animated: animated)
            myTableViewController.setRows(model.objects)
        default:
            navigationItem.setRightBarButton(nil, animated: animated)
    }
}

When didTransition(from:animated:) is called, a state transition has finished successfully. This is a good time to invoke other methods which in turn will trigger another state transition.

override func didTransition(from previousState: State?, animated: Bool) {
    switch currentState {
        case .loading:
            fetchData { model in
                self.setNeedsTransition(to: .ready(model), animated: true)
            }
        defualt:
            break
    }
}

Your StateViewController is now ready, and will switch between view controllers depending on state. Using setNeedsTransition(:to:animated:) you can transition between various states during the life cycle of your state view controller subclass.

Multiple other callbacks are available for determining when a child view controller is appearing or disappearing. Please reference the documentation or the Example.

Providing transitions between child view controllers

Child view controllers of StateViewController conforming to the StateViewControllerTransitioning protocol can individually control their own transition. The available methods provide functionality for:

  • Specifying duration and delayed start of an animated transition
  • Preparing the view controller for presentation
  • Performing animations along side an animated transition
  • Performing operations after a transition

Example

In the example application included in this project the state view controller switches between two view controllers. Firstly, it displays and animates the transition of an activity indicator view controller while a network call is being performed. Once the network call is successfully completed it transitions into a state displaying a table view with the loaded content.

Contribute

Please feel welcome contributing to StateViewController, check the LICENSE file for more info.

Credits

David Ask

You might also like...
YARCH iOS Architecture
YARCH iOS Architecture

YARCH is an architecture pattern developed primarly for iOS applications. You can ask any questions in our telegram channel. Russian version of the re

Sample applications of iOS Design patterns written using swift.

ios-design-patterns This repo contains all my Sample applications of iOS Design patterns written using swift. Link for my Design patterns Blog : https

A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view.

SwiftUI Hooks A SwiftUI implementation of React Hooks. Enhances reusability of stateful logic and gives state and lifecycle to function view. Introduc

Stateful WebView for SwiftUI.
Stateful WebView for SwiftUI.

Stateful SwiftUI WebView for iOS and MacOS Fully functional, SwiftUI-ready WebView for iOS 13+ and MacOS 10.15+. Actions and state are both delivered

A controller that uses a UIStackView and view controller composition to display content in a list
A controller that uses a UIStackView and view controller composition to display content in a list

StackViewController Overview StackViewController is a Swift framework that simplifies the process of building forms and other static content using UIS

Light and scrollable view controller for tvOS to present blocks of text
Light and scrollable view controller for tvOS to present blocks of text

TvOSTextViewer Light and scrollable view controller for tvOS to present blocks of text Description TvOSTextViewer is a view controller to present bloc

iOS routing done right. Handles both URL recognition and controller displaying with parsed parameters. All in one line, controller stack preserved automatically!
iOS routing done right. Handles both URL recognition and controller displaying with parsed parameters. All in one line, controller stack preserved automatically!

Developed and Maintained by Ipodishima Founder & CTO at Wasappli Inc. (If you need to develop an app, get in touch with our team!) So what is this lib

Mimicrate to native UIPageViewController. Each page is new controller, it can be even navigation controller.
Mimicrate to native UIPageViewController. Each page is new controller, it can be even navigation controller.

Mimicrate to native UIPageViewController. Each page is new controller, it can be even navigation controller. Support parent layout margins, paging and scroll by index. Don't have bug with tranlation when rotate.

SwiftMessages is a very flexible view and view controller presentation library for iOS.
SwiftMessages is a very flexible view and view controller presentation library for iOS.

SwiftMessages Overview SwiftMessages is a very flexible view and view controller presentation library for iOS. Message views and view controllers can

Paging view controller and scroll tab view
Paging view controller and scroll tab view

TabPageViewController Description TabPageViewController is paging view controller and scroll tab view. Screenshot Infinity Mode Limited Mode Customiza

A paging menu controller built from other view controllers placed inside a scroll view (like Spotify, Windows Phone, Instagram)
A paging menu controller built from other view controllers placed inside a scroll view (like Spotify, Windows Phone, Instagram)

Unfortunately, life gets in the way sometimes and I won't be able to maintain this library any longer and upgrade this library to where it needs to be

XLPagerTabStrip is a Container View Controller that allows us to switch easily among a collection of view controllers
XLPagerTabStrip is a Container View Controller that allows us to switch easily among a collection of view controllers

XLPagerTabStrip is a Container View Controller that allows us to switch easily among a collection of view controllers. Pan gesture can be used to move on to next or previous view controller. It shows a interactive indicator of the current, previous, next child view controllers.

A fully customizable container view controller to display a set of ViewControllers in a horizontal scroll view. Written in Swift.
A fully customizable container view controller to display a set of ViewControllers in a horizontal scroll view. Written in Swift.

DTPagerController This is a control for iOS written in Swift. DTPagerController is simple to use and easy to customize. Screenshots Default segmented

A fully customizable container view controller to display a set of ViewControllers in a horizontal scroll view. Written in Swift.
A fully customizable container view controller to display a set of ViewControllers in a horizontal scroll view. Written in Swift.

DTPagerController This is a control for iOS written in Swift. DTPagerController is simple to use and easy to customize. Screenshots Default segmented

UIViewController extension to present view / view controller as bottom-half modal.
UIViewController extension to present view / view controller as bottom-half modal.

UIViewController extension to present view / view controller as bottom-half modal. Installation CocoaPods pod 'SemiModalViewController' Swift Package

SwiftySideMenu is a lightweight and easy to use side menu controller to add left menu and center view controllers with scale animation based on Pop framework.
SwiftySideMenu is a lightweight and easy to use side menu controller to add left menu and center view controllers with scale animation based on Pop framework.

SwiftySideMenu SwiftySideMenu is a lightweight, fully customizable, and easy to use controller to add left menu and center view controllers with scale

Easily hide and show a view controller's navigation bar (and tab bar) as a user scrolls
Easily hide and show a view controller's navigation bar (and tab bar) as a user scrolls

HidingNavigationBar An easy to use library (written in Swift) that manages hiding and showing a navigation bar as a user scrolls. Features Usage Custo

A modal passcode input and validation view controller for iOS
A modal passcode input and validation view controller for iOS

TOPasscodeViewController A modal passcode input and validation view controller for iOS. TOPasscodeViewController is an open-source UIViewController su

A library of custom iOS View Controller Animations and Interactions.
A library of custom iOS View Controller Animations and Interactions.

RZTransitions is a library to help make iOS7 custom View Controller transitions slick and simple. Installation CocoaPods (Recommended) Add the followi

Comments
  • Strongly App

    Strongly App

    Hi David, The issue is unrelated to the current repo and it's about your "strongly" app. I thought it was the fastest way to contact you.

    I believe it's the most beautiful app to track a workout routine and there's nothing similar to this in the app store.

    Unfortunately, I cannot buy the Pro version, the button doesn't work.

    Could you please take a look at it? Thanks a lot, Ihor

    opened by kodburn 0
Releases(2.0.0)
Owner
David Ask
iOS developer at heart, former art director. Available for hire.
David Ask
This repository contains a detailed sample app that implements VIPER architecture in iOS using libraries and frameworks like Alamofire, AlamofireImage, PKHUD, CoreData etc.

iOS Viper Architecture: Sample App This repository contains a detailed sample app that implements VIPER architecture using libraries and frameworks li

MindOrks 653 Jan 2, 2023
A holistic approach to iOS development, inspired by Redux and MVVM

Tempura is a holistic approach to iOS development, it borrows concepts from Redux (through Katana) and MVVM. ?? Installation Requirements CocoaPods Sw

Bending Spoons 693 Jan 4, 2023
A collection of iOS architectures - MVC, MVVM, MVVM+RxSwift, VIPER, RIBs and many others

ios-architecture WIP ?? ?? ?? ??️ Demystifying MVC, MVVM, VIPER, RIBs and many others A collection of simple one screen apps to showcase and discuss d

Pawel Krawiec 1.3k Jan 3, 2023
Spin aims to provide a versatile Feedback Loop implementation working with the three main reactive frameworks available in the Swift community (RxSwift, ReactiveSwift and Combine)

With the introduction of Combine and SwiftUI, we will face some transition periods in our code base. Our applications will use both Combine and a thir

Spinners 119 Dec 29, 2022
A Swift 4.2 VIPER Module Boilerplate Generator with predefined functions and a BaseViewProtocol.

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. Are you new to VIPER Design Pattern? Want

Mohamad Kaakati 68 Sep 29, 2022
SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.

Articles related to this project Clean Architecture for SwiftUI Programmatic navigation in SwiftUI project Separation of Concerns in Software Design C

Alexey Naumov 4k Dec 31, 2022
This is an example of clean architecture and MVVM pattern written in swift

Swift Clean Architecture MVVM This is an example of clean architecture and MVVM pattern written in swift First of all thanks to all of those who made

null 19 Oct 12, 2022
Example of Clean Architecture of iOS app using RxSwift

Clean architecture with RxSwift Contributions are welcome and highly appreciated!! You can do this by: opening an issue to discuss the current solutio

null 3.6k Dec 29, 2022
Reactant is a reactive architecture for iOS

Reactant Reactant is a foundation for rapid and safe iOS development. It allows you to cut down your development costs by improving reusability, testa

Brightify 374 Nov 22, 2022
Viper Framework for iOS using Swift

Write an iOS app following VIPER architecture. But in an easy way. Viper the easy way We all know Viper is cool. But we also know that it's hard to se

Ferran Abelló 504 Dec 31, 2022