Skip to content

Instantly share code, notes, and snippets.

@dnedrow
Last active March 9, 2020 13:41
Show Gist options
  • Select an option

  • Save dnedrow/ebb68dbc0a38f78a063a60445ca233d4 to your computer and use it in GitHub Desktop.

Select an option

Save dnedrow/ebb68dbc0a38f78a063a60445ca233d4 to your computer and use it in GitHub Desktop.
"Stored properties" for Swift
// Created by Nedrow, David E on 2/21/18.
// This work is licensed under Attribution 4.0 International (CC 4.0)
import Foundation
/// Mechanism that provides something resembling stored properties for extensions.
///
/// Usage:
///
/// 1. Extend your class with the PropertyStoring protocol.
/// 2. Create a private struct containing the properties to be used.
/// 3. Implement a public var{get{} set{}} for each of the private properties.
///
/// Example:
/// ```
/// protocol ToggleProtocol {
/// func toggle()
/// }
///
/// enum ToggleState {
/// case on
/// case off
/// }
///
/// extension UIButton: ToggleProtocol, PropertyStoring {
///
/// private struct CustomProperties {
/// static var toggleState = false
/// }
///
/// var toggleState: ToggleState {
/// get {
/// return getAssociatedObject(&CustomProperties.hidden, defaultValue: CustomProperties.hidden)
/// }
/// set {
/// return objc_setAssociatedObject(self, &CustomProperties.hidden, newValue, .OBJC_ASSOCIATION_RETAIN)
/// }
/// }
///
/// func toggle() {
/// toggleState = toggleState == .on ? .off : .on
///
/// if toggleState == .on {
/// // Shows background for status on
/// } else {
/// // Shows background for status off
/// }
/// }
/// }
/// ```
protocol PropertyStoring {
/// Returns the value associated with a given object for a given key.
///
/// - Parameters:
/// - object: The source object for the association.
/// - key: The key for the association.
/// - defaultValue: Value to return if association not found.
/// - Returns: The value associated with the key for the object.
/// - SeeAlso:
/// [objc_getAssociatedObject](https://developer.apple.com/documentation/objectivec/1418865-objc_getassociatedobject)
func getAssociated<T>(_ object: Any!, _ key: UnsafeRawPointer!, defaultValue: T) -> T
/// Sets an associated value for a given object using a given key and association policy.
///
/// - Parameters:
/// - object: The source object for the association.
/// - value: The value to associate with the key key for object. Pass nil to clear an existing association.
/// - associativeKey: The key for the association.
/// - policy: The policy for the association. For possible values, see [Associated Objects](http://nshipster.com/associated-objects/)
/// SeeAlso:
/// [objc_setAssociatedObject](https://developer.apple.com/documentation/objectivec/1418509-objc_setassociatedobject)
func setAssociated<T>(object: AnyObject, value: T, associativeKey: UnsafeRawPointer, policy: objc_AssociationPolicy)
}
extension PropertyStoring {
func getAssociated<T>(_ object: Any!, _ key: UnsafeRawPointer!, defaultValue: T) -> T {
guard let value: T = objc_getAssociatedObject(object, key) as? T else {
return defaultValue
}
return value
}
func setAssociated<T>(object: AnyObject, value: T, associativeKey: UnsafeRawPointer, policy: objc_AssociationPolicy) {
objc_setAssociatedObject(object, associativeKey, value, policy)
}
}
// This work is licensed under Attribution 4.0 International (CC 4.0)
// You are free to:
// Share — copy and redistribute the material in any medium or format
// Adapt — remix, transform, and build upon the material
// for any purpose, even commercially.
//
// This license is acceptable for Free Cultural Works.
// The licensor cannot revoke these freedoms as long as you follow the license terms.
// See https://creativecommons.org/licenses/by/4.0/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment