Facebook Tweaks with Swift Tutorial
Learn how to use Facebook Tweaks, which allows you to modify parameters in your code whilst the app is running, and to enable or disable features on the fly. By .
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Facebook Tweaks with Swift Tutorial
30 mins
More Complicated Tweaks
One of your testers said that the label text should be bigger. You could use the method you already have to add a tweak for the font size, but there’s a cooler way to go about it.
You’ll add a tweak that executes a closure when the tester changes a tweak value — a tweak with action, if you will.
Instances of FBTweak can have observers. When the value of a tweak changes, the method tweakDidChange(tweak: FBTweak)
is called on all observers. You’ll use this to implement the tweak with action.
Open Tweaks.swift and change the following line:
class Tweaks {
To this:
class Tweaks: NSObject, FBTweakObserver {
With this change, you tell the compiler that Tweaks
will implement tweakDidChange
.
Now, add the following to the beginning of the Tweaks
class in Tweaks.swift:
typealias ActionWithValue = ((currentValue: AnyObject) -> ())
var actionsWithValue = [String:ActionWithValue]()
The variable actionsWithValue
is a dictionary that stores functions with a parameter of type AnyObject
and a return value of ()
.
Now, add the following method to the class:
func tweakActionForCategory<T where T: AnyObject>(categoryName: String, collectionName: String, name: String, defaultValue: T, minimumValue: T? = nil, maximumValue: T? = nil, action: (currentValue: AnyObject) -> ()) {
let identifier = categoryName.lowercaseString + "." + collectionName.lowercaseString + "." + name
let collection = Tweaks.collectionWithName(collectionName, categoryName: categoryName)
var tweak = collection.tweakWithIdentifier(identifier)
if tweak == nil {
tweak = FBTweak(identifier: identifier)
tweak.name = name
tweak.defaultValue = defaultValue
if minimumValue != nil && maximumValue != nil {
tweak.minimumValue = minimumValue
tweak.maximumValue = maximumValue
}
tweak.addObserver(self)
collection.addTweak(tweak)
}
actionsWithValue[identifier] = action
action(currentValue: tweak.currentValue ?? tweak.defaultValue)
}
The method tweakActionForCategory(...)
looks very similar to tweakValueForCategory(...)
. However, the difference is that it has an additional parameter, action: (currentValue: AnyObject) -> ()
, that is added to the dictionary actionsWithValue
within the method body.
The instance of the Tweaks class (self
) is added as an observer to the tweak. This means when a tweak that was added via this method is changed, the method tweakDidChange(...)
on the instance is called.
Finally, add the following:
func tweakDidChange(tweak: FBTweak!) {
let action = actionsWithValue[tweak.identifier]
action?(currentValue: tweak.currentValue ?? tweak.defaultValue)
}
In tweakDidChange(...)
, you use the tweak identifier to retrieve the action for this tweak from the actionsWithValue
dictionary. This action is then executed with the current value, provided it’s not nil
, otherwise it’s set to the default value.
To get this tweak with action to work, you need an instance of the Tweaks
class in ViewController.swift.
Go to the beginning of the class ViewController
and add:
let tweaks = Tweaks()
Now add the following code in viewDidLoad
:
tweaks.tweakActionForCategory("Jar View", collectionName: "Coin Label", name: "Text Size", defaultValue: 30, minimumValue: 20, maximumValue: 60, action: { (currentValue) -> () in
self.coinLabel.font = self.coinLabel.font.fontWithSize(CGFloat(currentValue.floatValue))
})
This code adds a tweak with ab action to the tweak store. When you change the value of the tweak, the action executes. In this case, you’re changing the font size of the coinLabel
to the current value of the tweak.
Build and run. Pull up the tweaks view controller. Change the font size to 60 and tap Done. You should see something like this:
Even More Tweaks
Add a few more tweaks, just to practice your new skills. Add the following code to viewDidLoad()
in ViewController.swift:
tweaks.tweakActionForCategory("Jar View", collectionName: "Coin Label", name: "Orange Text", defaultValue: false, action: { (currentValue) -> () in
if currentValue.boolValue == true {
self.coinLabel.textColor = UIColor(red: 0.98, green: 0.58, blue: 0.13, alpha: 1.0)
} else {
self.coinLabel.textColor = UIColor.blackColor()
}
})
This tweak lets you toggle the text color of the coinLabel
.
How would the app look if you were to change the gravity? Well, add a tweak for it and find out. Back within viewDidLoad()
, find the closure of the startAccelerometerUpdatesToQueue
method of motionManager
, and replace these two lines:
let y = CGFloat(data.acceleration.y)
let x = CGFloat(data.acceleration.x)
With the following:
let magnitude = CGFloat(Tweaks.tweakValueForCategory("Jar View", collectionName: "Dynamics", name: "Gravity Magnitude", defaultValue: 1.0).floatValue)
let y = magnitude * CGFloat(data.acceleration.y)
let x = magnitude * CGFloat(data.acceleration.x)
This tweak gives you and your testers control of a fundamental element — gravity! It’s like being a super hero! Unfortunately, this only works when you test on a device as the simulator doesn’t have an accelerometer and the iPhone doesn’t know how to defy gravity — yet.
Play around with the tweaks and find the values that make the app behave and look its best.
Production Code
I recommend you remove the tweaks code as soon as you settle on the right values. But just in case you forget or something weird happens, like you have one beer too many and decide to publish your app after letting your friends tweak it, you should add code to disable tweaks in your release builds.
Select your project in the Project Navigator and then open Build Settings. Search for other swift. Add the value -DDEBUG in Other Swift Flags to the Debug configuration, as shown here:
With this addition, you can use preprocessor directives to disable Tweaks in release builds.
Open AppDelegate.swift and replace the existing definition of window
with the following:
#if DEBUG
lazy var window: UIWindow? = {
let window = FBTweakShakeWindow(frame: UIScreen.mainScreen().bounds)
return window
}()
#else
var window: UIWindow?
#endif
Now go to Tweaks.swift and add #if DEBUG
at the beginning of both tweakActionForCategory(...)
and tweakValueForCategory(...)
. At the end of the method tweakActionForCategory(...)
, add the lines:
#else
action(currentValue: defaultValue)
#endif
And add this at the end of tweakValueForCategory(...)
:
#else
return defaultValue
#endif
Now, when you make a release build, the tweaks fall back to default values. So even if you do publish your app when you shouldn’t the worst you’ll do is publish it exactly how you developed it to be.