adam tecle

stored properties in extensions

A neat workaround to get stored properties in extensions is to use associated objects. You can do it in Swift like this:

extension MyObject {
    var property: Any? { 
        get { 
            return objc_getAssociatedObject(self, &key)  
        }
        set(newValue) {
          objc_setAssociatedObject(self, &key, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

A possible application of this in practice is to add some functionality for all instances of an object. Here’s how you can add a showLoadingIndicator() method to every UIView.


extension UIView {
  
  var loadingIndicator: LoadingIndicator? {
    get {
      guard let object = objc_getAssociatedObject(self, &key) as? LoadingIndicator else {
        return nil
      }

      return object
    }
    set(newValue) {
      objc_setAssociatedObject(self, &key, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
  
  func showLoadingIndicator() {
    setupIfNeeded()
    loadingIndicator?.isHidden = false
  }

  func hideLoadingIndicator() {
    loadingIndicator?.isHidden = true
  }

  private func setupIfNeeded() { ... }
  
}

Although this is really cool, it’s definitely feels...dirty, and unsafe. There are nicer ways of adding functionality to a class than resorting to runtime magic.

That being said, here’s a convenient way to pretty up your syntax when getting/setting associated object by using a generic helper class, credit to Wojciech Nagrodzki

public final class Association<T: AnyObject> {

    private let policy: objc_AssociationPolicy

    /// - Parameter policy: An association policy that will be used when linking objects.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

        self.policy = policy
    }

    /// Accesses associated object.
    /// - Parameter index: An object whose associated object is to be accessed.
    public subscript(index: AnyObject) -> T? {

        get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

Now instead of those scary Objective-C runtime library methods, we have this nice subscript syntax.

extension SomeType {

    private static let association = Association<NSObject>()

    var simulatedProperty: NSObject? {

        get { return SomeType.association[self] }
        set { SomeType.association[self] = newValue }
    }
}


Hi internet guest, I’m Adam. I’m a software engineer based in Brooklyn, NY. I specialize in iOS development, but I have some experience with Android and across the stack with a variety of languages and technologies.

Some things I’ve made

Hire me

I’m available for freelance work! I love collaborating with teams and individuals that are building great products.

Don’t hesitate to get in touch.