Thursday, 5 May 2016

Type-safe styles in Swift

TL;DR - By leveraging generics it's possible to create type-safe state values for the different states of a view
Views in a application will be styled and branded and looking slightly differently depending on the state they are in. For example, for a button that is disabled the label may be greyed out and the shadow removed. Sometimes even the font could change when the state changes. We can leverage generics in Swift to encapsulate this concept.
The first thing to do is to create a generic struct that will encapsulate the values for the different states. Note that this struct will be specialised with anything relevant for a state, e.g. UIColorUIFont, etc. In the following struct I've only defined 3 states, normalhighlighted and disabled but there could as many or as few as it's needed since they are optional.
struct StateValue<T> {
  private let normal: T?
  private let highlighted: T?
  private let disabled: T?
  init(normal: T? = nil, highlighted: T? = nil, disabled: T? = nil) {
    self.normal = normal
    self.highlighted = highlighted
    self.disabled = disabled
To be able to improve how the StateValue struct is used I created an enum that represents some of the states a view could be in. This list matches the previous states thought it doesn't necessarily have to. Again, it's certainly not an exhaustive list, it only covers the relevant states for this example.
enum ViewState {
  case Normal
  case Highlighted
  case Disabled
We can then extend the StateValue so that we can access the value for a specific ViewState. I have used a subscript for this because it provides a cleared interface than a function.
extension StateValue {
  subscript (state: ViewState) -> T? {
    switch state {
    case .Normal:
      return normal
    case .Highlighted:
      return highlighted
    case .Disabled:
      return disabled
Now that all the building blocks are defined we can use them to extend any views we would want. For example, UIButton could be extended to have a method that will set the colour of the title for all states.
extension UIButton {
  func new_setTitleColor(stateValue: StateValue<UIColor>) {
    setTitleColor(stateValue[.Normal], forState: .Normal)
    setTitleColor(stateValue[.Highlighted], forState: .Highlighted)
    setTitleColor(stateValue[.Disabled], forState: .Disabled)
Putting all this together into a playground and using the new interactive playgrounds for the button it's possible to show this in action.
import UIKit
import XCPlayground

class Target : NSObject {
  func action() {
    print("Button pressed!")

let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
containerView.backgroundColor = .whiteColor()
XCPlaygroundPage.currentPage.liveView = containerView
let target = Target()

let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .lightGrayColor()
button.setTitle("Some button", forState: .Normal)
button.addTarget(target, action: #selector(Target.action), forControlEvents: .TouchUpInside)

let buttonState: StateValue<UIColor> = StateValue(normal: .purpleColor(), highlighted: .greenColor(), disabled: .redColor())
// button.enabled = false // This would make the button red
The previous example is one of the ways the StateValue can be used. Equally this could be used for encapsulating the themes of different types in your application. This is a lot clearer with an example. Let's say we have an Vehicle enum:
enum Vehicle {
  case Car
  case Airplane
Let's say in our application the button for a Car looks different than the button from a Airplane and they are both displayed in some form of dynamic view (e.g. a UITableView of many Cars and Airplanes). To style each of the buttons of the cell we could extend Vehicle using a new Stylable protocol and define the StateValue for each of the Vehicle. Note that the Stylable protocol is not strictly needed, it's just a way to have named extensions that are clear to read and make our code more generic and reusable.
protocol Stylable {
  var buttonColor: StateValue<UIColor> { get }

extension Vehicle : Stylable {
  var buttonColor: StateValue<UIColor>  {
    switch self {
    case .Car:
      return StateValue(normal: .yellowColor(), highlighted: .blueColor(), disabled: .grayColor())
    case .Airplane:
      return StateValue(normal: .purpleColor(), highlighted: .greenColor(), disabled: .redColor())
The buttonColor on a Vehicle could be used in the following way (Bare in mind this is quick example to show the concept in action). 
let vehicleButton = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))

func setTitleColorForStylableItem(stylable: Stylable) {

let car = Vehicle.Car
All in all, if you have a lot of styling in your app for the various states and types of object using a generic StateValue struct is a great way to encapsulate all this logic. One of the advantages is that because it's generic it can be used for anything relevant to your style as mentioned originally; UIColors, UIFonts, UIImage, etc. I believe this is a great pattern that can be extended in way that will suit your needs very easily.


  1. My friend just shared this post with me and I really liked it. This is very helpful. Thanks for sharing this post with us. I really liked it.

  2. Hi,Nice blog.Thank you so much for sharing this.If you are looking for an used car please visit us

  3. Wheely | The largest platform to play wheely online games in 2019. We have a number of fun games for kids both boys and girls. more info click my blog

  4. We are a local Disaster Restoration Company that provides emergency services for Residential and Commercial Properties in the Sarasota and Manatee county areas. Key Cities are Bradenton, Sarasota, Palmetto, Venice, Lakewood Ranch, and Osprey. We are Mold, Water, Odor, Cleaning Specialist. Detail Cleaning Company. visit my blog Venice Fl Water Damage Experts

  5. Swagg Sauce, manufacturer of the finest premium vape juice and salt nicotine ingredients crafted with our signature flavor blends and eliquid online. Premium grade vape juice, candy, cream, custard, dessert, fruit, tobacco, menthol and more. Click Here

  6. Known as one of the Top Plastic Surgeon in Connecticut, Dr. Foster is known for his skill in Liposuction, Tummy Tucks, and hair surgeries. Call today 203-577. visit her

  7. If you’re looking for a woodworking company, Leander Woodworks north and west of Austin, TX is the best choice. Many homeowners turn to us for quality woodwork projects go to

  8. My friend just shared this post with me and I really liked it. This is very helpful. Thanks for sharing this post with us.