swift-foundation-extensions

CI SwiftPM 5.9 Platforms @capture_context

Foundation 框架的标准扩展

目录

编码 (Coding)

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

NSLocking

Optional (可选类型)

撤销/重做管理 (Undo/Redo management)

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 == 2

Indirect (间接)

CoW 容器,允许您递归地包含值类型的单个实例

struct ListNode<Value> {
  var value: Value
  
	@Indirect
  var next: ListNode<Value>?
}

PropertyProxy (属性代理)

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

对象关联 (Object Association)

基本对象关联助手函数在基础包中可用

extension UIViewController {
  var someStoredProperty: Int {
    get { getAssociatedObject(forKey: #function).or(0) }
    set { setAssociatedObject(newValue, forKey: #function)  }
  }
}

let value: Bool = getAssociatedObject(forKey: "value", from: object)

FoundationExtensionsMacros 目标提供了关联对象的全部功能

默认情况下,@AssociatedObject 宏对类使用 .retain(.nonatomic),对结构体使用 .copy(.nonatomic) objc_AssociationPolicy

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

宏需要 swift-syntax 编译,因此会影响冷编译时间

方法交换 (Swizzling)

此包还为 objc 方法交换提供了一些语法糖 (sugar)

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

安装

基础

您可以通过将其作为包依赖项添加到 Xcode 项目来添加 FoundationExtensions。

  1. File 菜单中,选择 Swift Packages › Add Package Dependency…
  2. "https://github.com/capturecontext/swift-foundation-extensions.git" 输入到包存储库 URL 文本字段中
  3. 选择您需要的产品并将它们链接到您的项目。

推荐

如果您为您的项目使用 SwiftPM,您可以将 StandardExtensions 添加到您的包文件中。

.package(
  url: "https://github.com/capturecontext/swift-foundation-extensions.git", 
  .upToNextMinor(from: "0.5.0")
)

不要忘记目标依赖项

.product(
  name: "FoundationExtensions", 
  package: "swift-foundation-extensions"
)
.product(
  name: "FoundationExtensionsMacros", 
  package: "swift-foundation-extensions"
)

许可证

此库在 MIT 许可证下发布。 有关详细信息,请参阅 LICENCE