Standard extensions for Foundation framework
- 
RawCodingKey allows you to create CodingKeys from literals 
- 
Extensions for encoder and decoder allow you to create an object with a contextual container 
- 
Extensions for coding containers automatically infer type from context 
init(from decoder: Decoder) throws {
  self = try container.decode(RawCodingKey.self) { container in
    return .init(
      someProperty1: container.decode("someProperty1"),
      someProperty2: container.decode("some_property_2")
    )
  }
}
func encode(to encoder: encoder) throws {
  try encoder.encode(RawCodingKey.self) { container in
    try container.encode(someProperty1, forKey: "someProperty1")
    try container.encode(someProperty2, forKey: "some_property_2")
  }
}- store(_:in:)- stores value in some variable in locked context
- mutate(_:with:)- passes given object to locked context
- assign(_:to:on:)- stores value in object property in locked context
- execute(_:)- provides new locked context
- orThrow(_:)- unwraps an optional or throws specified error
- isNil/- isNotNil/- isNilOrEmpty
- or()- coalesing alias
- unwrap()- returns unwrapping Result
- assign(to:on:)- assigns wrapped value to a specified target property by the keyPath
- ifLetAssign(to:on:)- assigns wrapped value to a specified target property by the keyPath if an optional was not nil
struct State {
  var value: Int = 0
}
@Resettable
let state = State()
state.value = 1   // value == 1
state.value *= 10 // value == 10
state.undo()      // value == 1
state.value += 1  // value == 2
state.undo()      // value == 1
state.redo()      // value == 2CoW container, which allows you to recursively include single instances of value types
struct ListNode<Value> {
  var value: Value
  
	@Indirect
  var next: ListNode<Value>?
}class MyView: UIView {
  private let label: UILabel
  
  @PropertyProxy(\MyView.label.text)
  var text: String?
}
let view: MyView = .init()
view.label.text // ❌
view.text = "Hello, World!"Basic helpers for object association are available in a base package
extension UIViewController {
  var someStoredProperty: Int {
    get { getAssociatedObject(forKey: #function).or(0) }
    set { setAssociatedObject(newValue, forKey: #function)  }
  }
}
let value: Bool = getAssociatedObject(forKey: "value", from: object)But the full power of associated objects is provided by FoundationExtensionsMacros target
By default
@AssociatedObjectmacro uses.retain(.nonatomic)for classes and.copy(.nonatomic)objc_AssociationPolicyfor structs.
import FoundationExtensionsMacros
extension SomeClass {
  @AssociatedObject
  var storedVariableInExtension: Int = 0
  
  @AssociatedObject(readonly: true)
  var storedVariableInExtension: SomeObject = .init()
  
  @AssociatedObject
  var optionalValue: Int?
  
  @AssociatedObject
  var object: Int?
    
  @AssociatedObject(threadSafety: .atomic)
  var threadSafeValue: Int?
    
  @AssociatedObject(threadSafety: .atomic)
  var threadSafeObject: Object?
    
  @AssociatedObject(policy: .assign)
  var customPolicyValue: Int?
    
  @AssociatedObject(policy: .retain(.atomic))
  var customPolicyThreadSafeObject: Object?
}Macros require swift-syntax compilation, so it will affect cold compilation time
This package also provides some sugar for objc method swizzling
extension UIViewController {
  // Runs once in app lifetime
  // Repeated calls do nothing
  private static let swizzle: Void = {
    // This example is not really representative since these methods
    // can be simply globally overriden, but it's just an example
    // for the readme and you can find live example at
    // https://github.com/capturecontext/combine-cocoa-navigation
    
    objc_exchangeImplementations(
    	#selector(viewWillAppear)
      #selector(__swizzledViewWillAppear)
    )
    
    objc_exchangeImplementations(
    	#selector(viewDidAppear)
      #selector(__swizzledViewDidAppear)
    )
  }()
  @objc dynamic
  private func __swizzledViewWillAppear(_ animated: Bool) {
    __swizzledViewWillAppear(animated) // calls original method
    print(type(of: self), ObjectIdentifier(self), "will appear")
  }
  @objc dynamic
  private func __swizzledViewDidAppear(_ animated: Bool) {
    __swizzledViewDidAppear(animated) // calls original method
    print(type(of: self), ObjectIdentifier(self), "did appear")
  }
}You can add FoundationExtensions to an Xcode project by adding it as a package dependency.
- From the File menu, select Swift Packages › Add Package Dependency…
- Enter "https://github.com/capturecontext/swift-foundation-extensions.git"into the package repository URL text field
- Choose products you need to link them to your project.
If you use SwiftPM for your project, you can add StandardExtensions to your package file.
.package(
  url: "https://github.com/capturecontext/swift-foundation-extensions.git", 
  .upToNextMinor(from: "0.5.0")
)Do not forget about target dependencies:
.product(
  name: "FoundationExtensions", 
  package: "swift-foundation-extensions"
).product(
  name: "FoundationExtensionsMacros", 
  package: "swift-foundation-extensions"
)This library is released under the MIT license. See LICENCE for details.