Introducing TemplateKit: Native UI Components in Swift

Matias Cudich
7 min readNov 29, 2016

--

React Native won’t cut it where it counts.

For iOS applications that matter, JavaScript won’t cut it. Because of this, I decided to build a native component framework in Swift focused on performance, ease of use and flexibility. It’s called TemplateKit.

I’ve been working in the iOS ecosystem since about 2008. I’ve worked on projects of varying size and complexity, including YouTube’s iOS app, whose team I led for a couple of years. One of the reasons some of us care about iOS is that it lets us build high-quality user experiences. These experiences are supported by the ability to instantly respond to a variety of sophisticated user gestures; the ability to render to the screen at 60 FPS; and so on. These things matter, especially when you’re shipping to users who expect the very best from your application.

Unfortunately, just because you know how to write Swift or Objective-C doesn’t mean you’re free and clear. UIKit is very powerful, but it also makes it very easy to shoot yourself in the foot.

Writing apps for the web is no different — just because you know JavaScript doesn’t mean you’ll ship a high-performance app. Luckily, some very smart people have come up with component frameworks (React, Vue.js, Ember, etc.) that let developers ship high-quality web apps by simply following convention. These tools make it easy to reason about how an app should function, and then take care of doing the least amount of work to get that to happen (yay diffing!). On iOS, however, we’ve mostly been left out in the cold. That is, until Facebook took it on.

Seeing the value of component-based development on the web, Facebook released a variant of React that targeted native-app developers called React Native. They decided that rather than porting React to Objective-C or Swift, they would instead let developers write parts of their native apps in JavaScript, which would get executed in a virtual machine:

The only difference in the mobile environment is that instead of running React in the browser and rendering to divs and spans, we run it in an embedded instance of JavaScriptCore inside our apps and render to higher-level platform-specific components. (source)

This novel approach was driven by several guiding factors: it allows sharing the existing React code base, allows easier cross-platform development, and neat things like live reloading — all worthy objectives. Not on this list, though, is anything about maximizing performance or the resulting quality of user experience.

Some developers have hit this wall when building apps with React Native:

However, when we started building the iOS app, the performance of the chat’s scroll view wasn’t satisfactory, especially for some active chat groups. We decided to use ComponentKit for chat and write the necessary bridges instead. (source)

This is a performance bottleneck that pure native apps don’t have, making it much easier for them to reach the holy grail of 60 FPS, especially on weaker devices … (source)

Due to this limitation, and the likely importance of performance for their main apps on iOS and Android, Facebook has either maintained or introduced native component frameworks. For example, Facebook recently announced Components for Android, which is a native port of React to Java. And on iOS, Facebook has continued investing in ComponentKit, a fully native variant of React.

Unlike Components for Android, ComponentKit was designed and announced before React Native, and has trailed in offering some of the key innovations offered by React like view reconciliation, live reloading, and markup-based rendering. More importantly though, ComponentKit is implemented in Objective-C++ and therefore cannot be used by anyone working in Swift.

While this may seem like a minor detail, it’s likely that most developers writing new iOS apps today will be choosing Swift (because Apple has invested considerably in it; because it’s designed to be very fast and type safe; because it’s a pleasure to write in; and so on), and thus will not be able to take advantage of the benefits of ComponentKit. This leaves only a JavaScript-based framework as a real option.

This is why I built TemplateKit.

TemplateKit offers developers a fully native, high-performance solution for building components for iOS in Swift. Rather than rolling UIs by hand, components provide a simple set of hooks where developers can easily express the look and functionality of a given piece of their application. Developers can then quickly compose these components to build up their application, and efficiently update what gets rendered to UIKit over time. I believe that having this sort of framework available on iOS will significantly increase developer productivity, and the quality and performance of the applications they build.

Features Overview

To support building modern iOS applications, TemplateKit provides developers the following core features:

  • It’s a native framework written from the ground up in Swift. If you like writing iOS apps in native code, then TemplateKit is probably a good fit for you.
  • It’s easy to give it a try. You don’t need to switch your entire application over to it. You can start by just replacing the tiniest parts of your code, and work up from there.
  • Templates let developers declare the contents of their applications using simple markup similar to HTML. Because templates can be loaded remotely, apps can be updated at runtime (and even after shipping to the App Store). Templates support data binding and simple expressions, allowing for developers to move view code entirely into markup.
  • Components allow developers to express how a given chunk of UI should look, how that UI should update when state changes, and handlers for how that state should change. Components are somewhat functional in the sense that they predictably output a render tree for a given state input. This model is very much inspired by React.
  • TemplateKit’s layout functionality brings CSS flexbox to iOS. Developers can express arbitrarily deep component trees via markup, set layout properties on the given nodes, and expect a predictable set of layout frames to be calculated. Layout calculations (which includes measuring text sizes) are executed entirely on background threads so that the main thread is freed up to do things like scroll or handle user events in a timely fashion.
  • When updating a component, TemplateKit calculates the minimum diff that should be applied to the UIKit-managed view layer. Minimizing the set of changes to UIViews frees up the main thread to do more important things.
  • TemplateKit has built-in support for animating properties. Animations are flushed to the UI tree 60 times per second, driven by changes to what gets rendered by a component on each frame tick. Animations couple nicely with diffing, in that only the changed properties are materialized as UIKit calls.
  • Almost all expensive operations are performed on background threads: layouts, sizing text, calculating diffs between virtual and materialized component trees, and so on.
  • CSS. You can style components using standard CSS, using all the selectors you know and love from the web (caveat — some features are still in progress). I believe this is not available in the other popular native frameworks mentioned above.
  • TemplateKit is designed to be extended — add your own components, your own native views, and so on.

A Simple Example

You define your UI using a simple markup language (similar to what you get using JSX in React), which is inspired by HTML and CSS. This UI definition is rendered into a tree of native elements.

Functionality and state is encapsulated into components, which do things like handle user events and flush state changes to the UI. Components have strongly typed State and Properties values, that are used to figure out what ends up getting pushed out to UIKit.

Rendering components is as easy as calling a render function, which asynchronously computes and flushes a component to the supplied container view.

How does it work?

At its core, TemplateKit is comprised of Element and Node instances. Elements are used to describe trees of nodes, which can be anything that implements the Node interface. Nodes are used to vend out and manage view hierarchies.

Out of the box, there are several Node implementations that make it easy to set up UI hierarchies: Component, ViewNode, and a set of native controls like buttons, text labels, text fields and so on.

Building a component is as simple as subclassing Component, overriding its render() function, and deciding the set of properties it might accept and use as part of rendering. render() simply needs to return a Template, which can be constructed programmatically, or via an XML document (or other custom payload). When it comes time to render your component into a view, you simply call UIKitRenderer.render, and pass in the view that should contain your component’s rendered output. This will in turn call render() on your component instance, compute the layout and styles for the view tree, build this tree and then apply the layout and styles to it as appropriate.

When it comes time to update your component’s state, you can call updateState(...) from within your component implementation. This function receives a function that is passed the current state value (each Component can declare a State type, in the same way it declares a Properties type). This function in turn enqueues an update to the component, which will cause it to re-render, taking into account whatever changes were made to the state. This update is intelligent, and compares the current incarnation of the rendered view tree against the proposed element tree. Only the deltas between these two are flushed out to UIKit.

Closing Remarks

I’m really excited about trying to break the rules a bit on how iOS apps are built. And I hope you are too. I’m also excited to get feedback on this. Please feel free to file issues on Github!

How to try it

You can get the code on Github here, or install via CocoaPods or Carthage.

Acknowledgements

Big parts of TemplateKit were inspired by work being done at Facebook: AsyncDisplayKit, React, IGListKit, etc. There are also some other projects out there that are working on similar ideas: Few.swift, Render, Jasonette. Check them out!

--

--