AssociatedObject

Swift 宏,用于允许在类扩展中进行变量声明。它通过包装 objc_getAssociatedObject/objc_setAssociatedObject 来实现。

Github issues Github forks Github stars Github top language

安装

SPM

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

CocoaPods

将以下内容添加到您的 Podfile 中。

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

pod install 后,您可以在您的项目中使用此宏。

此外,如果您遇到类似 Expansion of macro 'AssociatedObject' did not produce a non-observing accessor 的构建错误。您应该检查您的项目设置 Build Settings-OTHER_SWIFT_FLAGS

应该有如下额外的标志。Alt text

如果不是,您可以自行添加这两行。

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

用法

例如,您可以通过声明以下内容向 UIViewController 添加新的存储属性

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"
}

声明的属性可以如下使用

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

        print(text) // => "text"

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

}

willSet/didSet

使用 @AssociatedObject 定义的属性可以实现 willSet 和 didSet。在 Swift 中,不可能同时实现 willSetdidSet 以及 setter,因此它们被扩展如下。

@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)
    }
}

许可证

AssociatedObject 在 MIT 许可证下发布。请参阅 LICENSE