KA Engineering

KA Engineering

We're the engineers behind Khan Academy. We're building a free, world-class education for anyone, anywhere.

Subscribe

Latest posts

Creating Query Components with Apollo

Brian Genisio on June 12

Migrating to a Mobile Monorepo for React Native

Jared Forsyth on May 29

Memcached-Backed Content Infrastructure

Ben Kraft on May 15

Profiling App Engine Memcached

Ben Kraft on May 1

App Engine Flex Language Shootout

Amos Latteier on April 17

What's New in OSS at Khan Academy

Brian Genisio on April 3

Automating App Store Screenshots

Bryan Clark on March 27

It's Okay to Break Things: Reflections on Khan Academy's Healthy Hackathon

Kimerie Green on March 6

Interning at Khan Academy: from student to intern

Shadaj Laddad on Dec 12, 2016

Prototyping with Framer

Nick Breen on Oct 3, 2016

Evolving our content infrastructure

William Chargin on Sep 19, 2016

Building a Really, Really Small Android App

Charlie Marsh on Aug 22, 2016

A Case for Time Tracking: Data Driven Time-Management

Oliver Northwood on Aug 8, 2016

Time Management at Khan Academy

Several Authors on Jul 25, 2016

Hackathons Can Be Healthy

Tom Yedwab on Jul 11, 2016

Ensuring transaction-safety in Google App Engine

Craig Silverstein on Jun 27, 2016

The User Write Lock: an Alternative to Transactions for Google App Engine

Craig Silverstein on Jun 20, 2016

Khan Academy's Engineering Principles

Ben Kamens on Jun 6, 2016

Minimizing the length of regular expressions, in practice

Craig Silverstein on May 23, 2016

Introducing SwiftTweaks

Bryan Clark on May 9, 2016

The Autonomous Dumbledore

Evy Kassirer on Apr 25, 2016

Engineering career development at Khan Academy

Ben Eater on Apr 11, 2016

Inline CSS at Khan Academy: Aphrodite

Jamie Wong on Mar 29, 2016

Starting Android at Khan Academy

Ben Komalo on Feb 29, 2016

Automating Highly Similar Translations

Kevin Barabash on Feb 15, 2016

The weekly snippet-server: open-sourced

Craig Silverstein on Feb 1, 2016

Stories from our latest intern class

2015 Interns on Dec 21, 2015

Kanbanning the LearnStorm Dev Process

Kevin Dangoor on Dec 7, 2015

Forgo JS packaging? Not so fast

Craig Silverstein on Nov 23, 2015

Switching to Slack

Benjamin Pollack on Nov 9, 2015

Receiving feedback as an intern at Khan Academy

David Wang on Oct 26, 2015

Schrödinger's deploys no more: how we update translations

Chelsea Voss on Oct 12, 2015

i18nize-templates: Internationalization After the Fact

Craig Silverstein on Sep 28, 2015

Making thumbnails fast

William Chargin on Sep 14, 2015

Copy-pasting more than just text

Sam Lau on Aug 31, 2015

No cheating allowed!!

Phillip Lemons on Aug 17, 2015

Fun with slope fields, css and react

Marcos Ojeda on Aug 5, 2015

Khan Academy: a new employee's primer

Riley Shaw on Jul 20, 2015

How wooden puzzles can destroy dev teams

John Sullivan on Jul 6, 2015

Babel in Khan Academy's i18n Toolchain

Kevin Barabash on Jun 22, 2015

tota11y - an accessibility visualization toolkit

Jordan Scales on Jun 8, 2015

Meta

Introducing SwiftTweaks

by Bryan Clark on May 9, 2016

Today, we’re releasing SwiftTweaks, a way to adjust your Swift-based iOS app without needing to recompile.

Overview of SwiftTweaks Your users won’t see your animation study, Sketch comps, or prototypes. What they will see is the finished product - so it’s really important to make sure that your app feels right on a real device!

Animations that look great on your laptop often feel too slow when in-hand. Layouts that looks perfect on a 27-inch display might be too cramped on a 4-inch device. Light gray text may look subtle in Sketch, but it’s downright illegible when you’re outside on a sunny day.

For these reasons, it’s helpful to fine-tune your designs on-device - but that’s a lot of work: open Xcode, tweak your code, and wait for the app to build to device before seeing the results.

What about Facebook Tweaks?

In Objective-C projects, I’ve cherished Facebook’s Tweaks, a tool that makes this process easy. However, while it's possible to use FBTweaks in Swift, it's far less convenient than in Objective-C.

Since Khan Academy’s iOS code is almost entirely Swift, we wanted something that would make it easy to use tweaks. (Plus: with Swift’s generic types, protocols, and all-around awesomeness, we figured we could make some improvements.)

We’ve been using SwiftTweaks for a few months now in our iOS app, and it’s been wonderful for fine-tuning gestures, adjusting animations, and toggling feature flags.

Using SwiftTweaks

Create a TweakLibrary

First, you create a TweakLibrary, which contains Tweaks and a TweakStore. (If TweakStore.enabled is false, then the Tweaks UI will be inaccessible and all tweaks return their default value - which means you can leave this code in-place when you ship your production app.)

public struct ExampleTweaks: TweakLibraryType {
    public static let colorTint = Tweak("General", "Colors", "Tint", UIColor.blueColor())
    public static let marginHorizontal = Tweak<CGFloat>("General", "Layout", "H. Margins", defaultValue: 15, min: 0)
    public static let marginVertical = Tweak<CGFloat>("General", "Layout", "V. Margins", defaultValue: 10, min: 0)
    public static let featureFlag = Tweak("Feature Flags", "Main Screen", "Show Body Text", true)

    public static let buttonAnimation = SpringAnimationTweakTemplate("Animation", "Button Animation")

    public static let defaultStore: TweakStore = {
        let allTweaks: [TweakType] = [colorTint, marginHorizontal, marginVertical, featureFlag]

        #if DEBUG
            let tweaksEnabled: Bool = true
        #else
            let tweaksEnabled: Bool = false
        #endif

        return TweakStore(
            tweaks: allTweaks.map(AnyTweak.init),
            enabled: tweaksEnabled
        )
    }()
}

Calling Tweaks in your code

When you want to use a tweak in your code, use the assign, bind, and bindMultiple functions.

assign returns the current value of the tweak:

button.tintColor = ExampleTweaks.assign(ExampleTweaks.colorTint)

bind calls its closure immediately, and again each time the tweak changes:

ExampleTweaks.bind(ExampleTweaks.colorTint) { button.tintColor = $0 }

bindMultiple calls its closure immediately, and again each time any of its tweaks change:

// A "multipleBind" is called initially, and each time _any_ of the included tweaks change:
let tweaksToWatch: [TweakType] = [ExampleTweaks.marginHorizontal, ExampleTweaks.marginVertical]
ExampleTweaks.bindMultiple(tweaksToWatch) {
    let horizontal = ExampleTweaks.assign(ExampleTweaks.marginHorizontal)
    let vertical = ExampleTweaks.assign(ExampleTweaks.marginVertical)
    scrollView.contentInset = UIEdgeInsets(top: vertical, right: horizontal, bottom: vertical, left: horizontal)
}

There are also several handy TweakGroupTemplate types, to help you with commonly-tweaked things. Our above ExampleTweaks library included one for a UIView spring animation:

public static let buttonAnimation = SpringAnimationTweakTemplate("Animation", "Button Animation")

This single line of code creates four tweaks - for duration, delay, damping, and initial spring velocity. Each has sensible defaults (e.g. “delay can’t be negative”) - and there’s a UIView extension to easily use the TweakGroup: UIView.animateWithSpringAnimationTweakTemplate

For more on using Tweaks and TweakGroupTemplates, check out the example project.

Accessing the interface

Lastly, we need a way to adjust our Tweaks while the app is running. The simplest way is to set your app’s UIWindow to be a TweakWindow. By default, the TweakWindow presents a TweaksViewController when you shake the device in a debug build, but you can provide a different gesture recognizer, too.

You can also handle the presentation of a TweaksViewController if you prefer to not use a TweakWindow.

Tweaking values

Now for the fun part - shake your phone, and your tweaks appear! Adjust booleans with a switch, numbers with a stepper or keyboard, and there’s a great color-editing interface in there, too! There’s also a “floating UI” so you can edit tweaks without leaving a screen.

Here's a preview of the SwiftTweaks example app (included in the repository): animated demo

Check it out on GitHub and let us know what you think!