Katana and Tempura: State, Dependencies and Store
Hi everybody, I’m Riccardo. Senior iOS Engineer at Bending Spoons, I breathe iOS development, both apps and tools and I love to share my knowledge with others.
This is the third part of how to create an app with Katana and Tempura, the two open-source libraries that are the core of the Bending Spoons’ iOS apps. You can find more about them in the previous articles:

Welcome back to another chapter of how to write an app with Katana and Tempura. Today, we will write the code of the main entities of our app: the State, the Dependencies, and the Store.
The State
It is the core of the app, where all the data is stored. For the App we are using as an example (see the previous article for details), the state will hold the latest results of the dice rolls and the history of all the rolls since the app was started. As every RPG player knows, we have a fixed set of dice: 4 sides, 6 sides, 8 sides, 10 sides, 12 sides, and 100 sides.
- Create a new group called State inside the DiceRoller folder.
- Press cmd+N to create a new file and select Swift File.
- Call it AppState.swift.
- Copy the following snippet below the import Foundation.
The Dependencies
The second element is the container for the dependencies. These are pieces of external code, usually coming from other libraries, or pieces of logic used to interact with the OS. Imagine, for example, that you have to use Apple’s In-App Purchases framework: you will probably need a manager to handle all the execution flows and it will stay in the dependencies.
In our case, we will use the dependencies to configure the Store and to handle the navigation.
- Create a new group called Dependencies.
- Press cmd+N to create a new file and select Swift File.
- Call it AppDependencies.swift.
- Copy the following snippet below the import Foundation.
In this piece of code, we are also declaring an object that will help us with the navigation. Now, we will see how we can configure the Store in order to start the app with a View Controller (VC).
The Store
The store is the main object that will manage the logic in our app: it owns the state and orchestrates the execution of StateUpdaters and SideEffects.
The Store must be configured in the AppDelegate. Therefore, open the AppDelegate.swift and replace the current code with the following:
First of all, we have to declare a store variable and we have to initialize it. This is done with an initializer that takes 2 parameters:
- An array of interceptors: these are functions that listen for some events that can happen within the store and let us dispatch some sideEffect to react to these events. We are passing an empty array for this app. Notice that Katana already offers 4 hooks to connect to the corresponding events: onStart, onDispatch, onNotification, onStateChange.
- A state initializer. This is something used to create the state when the application bootstraps. This is used to restore the state of a previous execution. At the moment, we are passing the init of the struct: we are not restoring the state from a previous execution.
The second step is to create a window, where the app will live.
The third step will move the app to the first screen. We are accessing the dependencies, created inside the store, to retrieve the navigator object. The start method requires three parameters:
- A root installer that installs a VC in the navigation hierarchy. We made the app delegate conforms to the RootInstaller protocol, that’s why we are passing self.
- A window, where the app will live, and we created one in step 2.
- The identifier of the screen we want to load. We have not created any UI yet, so we are going to use a simple String to identify it. Of course, there are better approaches and we will see them next week.
Finally, we have to implement the Tempura’s installRoot(…) method. Its logic is pretty simple: it has to recognize the VC we have to load, instantiate it and set it as the new window’s rootViewController so that the app can start. Then, we have to inform Tempura that the navigation has been managed by invoking the completion callback and returning true.
If the root installer does not know which screen to load, it just returns false. Notice that the app will crash because the navigation has not been handled. This is a programmatic error: we should always be able to handle all the navigation paths!
If we press the play button now, we will see the simulator displaying a green screen! Good job everybody!
There are a couple more concepts that are important to explain: how to write the UI and the logic. Hang with me, next week we will finish the tutorial, actually rolling some dice!