Working easier with tags

:  ~ 1 min read

One usual approach is to create an enum, so your tags are more expressive by having a name:

enum ViewTag: Int {
  case none
  case titleLabel
  case loginButton
}

Then tagging and retrieving views by tag will be safer, and easier to remember:

let container = UIView()

let titleLabel = UILabel()
container.addSubview(titleLabel)
titleLabel.tag = ViewTag.titleLabel.rawValue

let loginButton = UIButton(type: .Custom)
container.addSubview(loginButton)
loginButton.tag = ViewTag.loginButton.rawValue

if
  let titleLabel = container.viewWithTag(ViewTag.titleLabel.rawValue) as? UILabel,
  let loginButton = container.viewWithTag(ViewTag.loginButton.rawValue) as? UIButton {
    // Do stuff.
}

This is already much better than triple checking that the titleLabel's tag really is 1 and not 2, but what if we can go a step further and improve this, by extending UIView?

extension UIView {

  func tag(with value: ViewTag) {
    tag = value.rawValue
  }

  func viewWithTag(_ tag: ViewTag) -> UIView? {
    return viewWithTag(tag.rawValue)
  }

  // Speaking of Swifty, we could also change the above in:
  func view(tagged tag: ViewTag) -> UIView? {
    return viewWithTag(tag.rawValue)
  }
}

So all of our code can be shorter, cleaner and prettier:

let titleLabel = UILabel()
view.addSubview(titleLabel)
titleLabel.tag(with: .titleLabel)

let loginButton = UIButton(type: .Custom)
view.addSubview(loginButton)
loginButton.tag(with: .loginLabel)

[...] // somewhere else

if
  let titleLabel = view.viewWithTag(.titleLabel) as? UILabel,
  let loginButton = view.view(tagged: .loginButton) as? UIButton {
    // Do stuff.
}