Swiftpack.co - Package - ReSwift/ReSwift-Router

Carthage compatible Platform support

A declarative router for ReSwift. Allows developers to declare routes in a similar manner as URLs are used on the web.

Using ReSwiftRouter you can navigate your app by defining the target location in the form of a URL-like sequence of identifiers:

    SetRouteAction(["TabBarViewController", StatsViewController.identifier])

About ReSwiftRouter

ReSwiftRouter is still under development and the API is neither complete nor stable at this point.

When building apps with ReSwift you should aim to cause all state changes through actions - this includes changes to the navigation state.

This requires to store the current navigation state within the app state and to use actions to trigger changes to that state - both is provided ReSwiftRouter.



You can install ReSwiftRouter via CocoaPods by adding it to your Podfile:


source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

pod 'ReSwift'
pod 'ReSwiftRouter'

And run pod install.


You can install ReSwiftRouter via Carthage by adding the following line to your Cartfile:

github "ReSwift/ReSwift-Router"


Extend your app state to include the navigation state:

import ReSwiftRouter

struct AppState: StateType {
    // other application state
    var navigationState: NavigationState

After you've initialized your store, create an instance of Router, passing in a reference to the store and to the root Routable. Additionally you will need to provide a closure that describes how to access the navigationState of your application state:

router = Router(store: mainStore, rootRoutable: RootRoutable(routable: rootViewController)) { state in 
	state.select { $0.navigationState }

We'll discuss Routable in the next main section.

Calling the Navigation Reducer

The NavigationReducer is provided as part of ReSwiftRouter. You need to call it from within your top-level reducer. Here's a simple example from the specs:

struct AppReducer: Reducer {
    func handleAction(action: Action, state: FakeAppState?) -> FakeAppState {
        return FakeAppState(
            navigationState: NavigationReducer.handleAction(action, state: state?.navigationState)

This will make reducer handle all routing relevant actions.

Implementing Routable

ReSwiftRouter works with routes that are defined, similar to URLs, as a sequence of elements e.g. ["Home", "User", "UserDetail"].

ReSwiftRouter is agnostic of the UI framework you are using - it uses Routables to implement that interaction.

Each route element is mapped to one responsible Routable. The Routable needs to be able to present a child, hide a child or replace a child with another child.

Here is the Routable protocol with the methods you should implement:

public protocol Routable {

    func push(
        _ element: RouteElement,
        animated: Bool,
        completion: @escaping RoutingCompletion) -> Routable

    func pop(
        _ element: RouteElement,
        animated: Bool,
        completion: @escaping RoutingCompletion)

    func change(
        _ from: RouteElement,
        to: RouteElement,
        animated: Bool,
        completion: @escaping RoutingCompletion) -> Routable


As part of initializing Router you need to pass the first Routable as an argument. That root Routable will be responsible for the first route element.

If e.g. you set the route of your application to ["Home"], your root Routable will be asked to present the view that corresponds to the element "Home".

When working on iOS with UIKit this would mean the Routable would need to set the rootViewController of the application.

Whenever a Routable presents a new route element, it needs to return a new Routable that will be responsible for managing the presented element. If you want to navigate from ["Home"] to ["Home", "Users"] the Routable responsible for the "Home" element will be asked to present the "User" element.

If your navigation stack uses a modal presentation for this transition, the implementation of Routable for the "Home" element might look like this:

func push(_ element: RouteElement, animated: Bool, completion: @escaping RoutingCompletion) -> Routable {

	if element == "User" {
		// 1.) Perform the transition
        userViewController = UIStoryboard(name: "Main", bundle: nil)
            .instantiateViewControllerWithIdentifier("UserViewController") as! Routable

		// 2.) Call the `completion` once the transition is complete
        presentViewController(userViewController, animated: false,
            completion: completion)

		// 3.) Return the Routable for the presented element. For convenience
		// this will often be the UIViewController itself. 
        return userViewController
   	// ...

func pop(_ element: RouteElement, animated: Bool, completion: @escaping RoutingCompletion)

	if element == "Home" {
    	dismissViewControllerAnimated(false, completion: completion)
    // ...

Calling the Completion Handler within Routables

ReSwiftRouter needs to throttle the navigation actions, since many UI frameworks including UIKit don't allow to perform multiple navigation steps in parallel. Therefor every method of Routable receives a completion handler. The router will not perform any further navigation actions until the completion handler is called.

Changing the Current Route

Currently the only way to change the current application route is by using the SetRouteAction and providing an absolute route. Here's a brief example:

@IBAction func cancelButtonTapped(sender: UIButton) {
        SetRouteAction(["TabBarViewController", StatsViewController.identifier])

As development continues, support for changing individual route elements will be added.


Compiling & Running tests

ReSwiftRouter uses Carthage for its development dependencies. To build or test any of the targets, run carthage bootstrap.


Stars: 448


Used By

Total: 0


0.7.1 - 2019-07-31 15:50:30

Fixes outdated Carthage.resolved. Now all package managers are on par again.

0.7.0 - 2019-07-31 14:20:08

Breaking API Changes:

  • Remove use of StandardAction and StandardActionConvertible (#82) - @hlineholm

    • Removes the compatibility of this with ReSwift-Recorder, which itself is being deprecated.
    • Ensures compatibility with latest versions of ReSwift which have removed these types.
  • Renamed argument labels for modern Swift conformance (#116) - @TaeJoongYoon

    • Renamed routingActionsForTransitionFrom(_ oldRoute:,newRoute:) method to routingActionsForTransition(from oldRoute:,to newRoute:)
    • Renamed routableIndexForRouteSegment(_ segment:) method to routableIndex(for segment:)


  • Update to Swift 5 -- @djtech42
  • Update to ReSwift 5.0.0 and fix project setup for SwiftPM & Carthage (#115, #124) - @djtech42, @DivineDominion

- 2017-10-01 20:14:35

- 2017-10-01 20:14:25

0.5.0 - 2016-11-24 16:21:22

Released: 11/24/2016


  • Swift 3.0.1 / Xcode 8.1 updates - @DivineDominion, @frranck

0.4.0 (Swift 3.0 Release) - 2016-09-21 16:33:33

This version supports Swift 3 for Swift 2.2 support use an earlier release.

Released: 09/21/2016

  • Swift 3 Migration - @Ben-G
  • Documentation Fix - @excitedhoney

0.3.1 - 2016-07-16 21:15:40

Released: 07/16/2016


Expose RouteHash initializer publicly - @Ben-G

0.3.0 - 2016-06-30 15:11:26

Released: 06/28/2016


  • Update syntax to Swift 2.3 - @mjarvis
  • Update to ReSwift 2.0.0 - @Ben-G

0.2.7 Make Carthage Work Again - 2016-03-24 05:00:50


Fix issue when checking out with Carthage (#20) - @Ben-G

0.2.6 - 2016-03-20 21:19:56

API Changes:

  • Provide route action that allows chosing between animated and un-animated route changes - @Ben-G
  • Provide API for setting associated data for a certain route. This enables passing state information to subroutes - @Ben-G


  • Update ReSwift Dependency to 1.0 - @Ben-G
  • Use a symbolic breakpoint in place of an assertionFailure for handling a stuck router - @Ben-G
  • Documentation Fix - @jschmid

- 2016-02-23 02:58:28

API Changes:

  • ReSwift-Router now uses the new substate selection API when subscribing to a store. As a result, the HasNavigationState protocol has been removed. This change also allows an app to have multiple routers. - @Ben-G

- 2016-01-23 22:51:36

Swift-Flow-Router is now ReSwift-Router.

- 2016-01-23 22:51:05

API Changes:

  • Due to the new requirement in ReSwift, that top level reducers need to be able to take an empty application state and return a hydrated one, NavigationReducer is no longer a top-level reducer. You now need to call it from within your app reducer. Refer to the docs for more details. - @Ben-G


  • Drop iOS Deployment target to 8.0 - @Ben-G
  • Add Support for watchOS, tvOS, OSX - @Ben-G
  • Documentation updates - @Ben-G

0.2.2 - 2016-01-16 03:32:40

Updates Swift Flow Router to work with Swift Flow 0.2.2.

- 2015-12-15 08:32:07