Swift Developer. Living and Xcoding in Brooklyn NY.

Blog

Managing Style Attributes

"Good code minimizes the impact of change."
- Dave Thomas (author, The Pragmatic Programmer )

I'm still exploring ways to more efficiently centralize and manage style attributes in my projects. The goal is to be able to change style attributes in as few places as possible whenever an update is made. For example, in an ideal world, if the design team decides to change the Hex value of a color or font specification on an application-wide basis, it would be nice to have a single point-of-update rather than try to figure out if and where to change these attributes in code or storyboards (or both!).

Lately, I've been gravitating toward using storyboards as a prototyping and wireframing tool, and setting and updating my style attributes in code. I'm sharing a few approaches I've come across recently. How exactly they're applied in practice is up to the individual developer or team, but hopefully someone out there finds some of these tips and tricks as useful as I did. 

 

NAMESPACED CONSTANTS

Jesse Squires has an excellent blog post on the versatility of namespaced constants. He provides a couple of neat examples of nesting static attributes and methods within a struct to manage color or even image attributes within a project. This can be extended to managing fonts or even a date formatter as well.

 

struct Font {
        static let Regular = "HelveticaNeue-Medium"
        static let Light = "HelveticaNeue-Light"
        static let Bold = "HelveticaNeue-Bold"
        static let CondensedBold = "HelveticaNeue-CondensedBold"
    }

    struct Text {
        static let dateFormatter: NSDateFormatter = {
        let _formatter = NSDateFormatter()
        _formatter.dateStyle = .ShortStyle
        _formatter.timeStyle = .NoStyle
        return _formatter
    }()

I've found the use of namespaced constants quite handy for the following reasons:

  • Versatility. This can provide a way to specify additional levels of granularity when using appearance proxies provides too broad of a brush stroke, yet maintain a centralized, consistent way of managing global attributes.
  • Readability. We get the benefit of a very convenient, logical dot notation to represent our hierarchy of style attributes, with the bonus of Xcode's autocomplete. This can save precious minutes (or hours!) of having to switch back-and-forth between separate documents/files and/or rely upon one's own memory when changing attributes on-the-fly.
  • Computational efficiency. For expensive, frequently-used objects (e.g. NSDateFormatters), the static let approach lazily instantiates objects only if and when they are first called and saves us some computational overhead. In the example project posted to Github, note how even though the table view cell is dequeued repeatedly, instantiation of the date formatter is actually wrapped in a  dispatch_once call behind the scenes:

 

Screen Shot 2016-01-21 at 8.55.05 AM.png

Setting styles in PROPERTY OBSERVERS

Another nice little standardization we can leverage, as pointed out by Natasha The Robot, is setting style attributes in the didSet observers of UI elements of storyboard outlets. This isn't limited to @IBOutlets, but can also be applied to UI elements that are set purely programatically, like so:

var locationLabel: UILabel! {
        didSet {
            locationLabel.textColor = StyleKit.TableViewController.TableViewCell.locationLabelTextColor()
            locationLabel.font = StyleKit.TableViewController.TableViewCell.locationLabelFont()
        }
    }

Again, it makes it much easier for you and your teammates to navigate project files when a logical, consistent set of guidelines are established to manage design attributes on a global basis.

UIAPPEARANCE

UIAppearance allows us to customize any elements that conform to the UIAppearance proxy on a global basis, or get a little more granular when using the appearanceWhenContainedInInstancesOfClasses variantFor example, you can set global navigation styling, and even specify the image to be used for the back button on a global basis!

UINavigationBar.appearance().barTintColor = UIColor.whiteColor()
    UINavigationBar.appearance().translucent = false
    UINavigationBar.appearance().titleTextAttributes = [
    NSFontAttributeName: UIFont(name: Text.Font.Bold, size: 20.0)!,
    NSForegroundColorAttributeName: Color.Green

    let image = UIImage(named: "NavigationBackBarButtonImage")
    let backButtonImage = image?.stretchableImageWithLeftCapWidth(15, topCapHeight: 0)
    UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, forState: .Normal, barMetrics: .Default)

 

See the short-and-sweet example project posted to Github. What do you think?

Would love to hear your thoughts as well as learn about other best practices out there. Please share any comments and suggestions for improvement, and pull requests are very welcome! 

nickdesign, iOS, Swift