Skip to content

πŸ”— Swift Macro for allowing variable declarations even in class extensions

License

Notifications You must be signed in to change notification settings

p-x9/AssociatedObject

Repository files navigation

AssociatedObject

Swift Macro for allowing variable declarations even in class extensions. It is implemented by wrapping objc_getAssociatedObject/objc_setAssociatedObject.

Github issues Github forks Github stars Github top language

Installation

SPM

.package(url: "https://github.com/p-x9/AssociatedObject", from: "0.10.3")

CocoaPods

Add below to your Podfile.

pod 'AssociatedObject', git: 'https://github.com/p-x9/AssociatedObject', tag: '0.10.3'

After pod install, you can use this Macro in your project.

Additionally, if you encounter build error like Expansion of macro 'AssociatedObject' did not produce a non-observing accessor. You should check your project setting Build Settings-OTHER_SWIFT_FLAGS.

There should be additional flags like so. Alt text

If not, you can add these two lines by yourself.

-load-plugin-executable
${PODS_ROOT}/AssociatedObject/Binary/AssociatedObjectPlugin#AssociatedObjectPlugin

Usage

For example, you can add a new stored property to UIViewController by declaring the following

import AssociatedObject

extension UIViewController {
    @AssociatedObject(.retain(nonatomic))
    var text = "text"

    /* OR */

    @AssociatedObject(.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    var text = "text"

    static var customKey = ""
    @AssociatedObject(.OBJC_ASSOCIATION_RETAIN_NONATOMIC, key: customKey)
    var somevar = "text"
}

Declared properties can be used as follows

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print(text) // => "text"

        text = "hello"
        print(text) // => "hello"
    }

}

willSet/didSet

Properties defined using @AssociatedObject can implement willSet and didSet. In swift, it is not possible to implement willSet and didSet at the same time as setter, so they are expanded as follows.

@AssociatedObject(.copy(nonatomic))
public var hello: String = "こんにけは" {
    didSet {
        print("didSet")
    }
    willSet {
        print("willSet: \(newValue)")
    }
}

// ↓↓↓ expand to ... ↓↓↓
public var hello: String = "こんにけは" {
    get {
        objc_getAssociatedObject(
            self,
            &Self.__associated_helloKey
        ) as? String
        ?? "こんにけは"
    }

    set {
        let willSet: (String) -> Void = { [self] newValue in
            print("willSet: \(newValue)")
        }
        willSet(newValue)

        let oldValue = hello

        objc_setAssociatedObject(
            self,
            &Self.__associated_helloKey,
            newValue,
            .copy(nonatomic)
        )

        let didSet: (String) -> Void = { [self] oldValue in
            print("didSet")
        }
        didSet(oldValue)
    }
}

License

AssociatedObject is released under the MIT License. See LICENSE

About

πŸ”— Swift Macro for allowing variable declarations even in class extensions

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published