Foundation 框架的标准扩展
RawCodingKey 允许您从字面量创建 CodingKeys
encoder 和 decoder 的扩展允许您创建具有上下文容器的对象
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")
}
}
store(_:in:)
- 在锁定的上下文中将值存储在某个变量中mutate(_:with:)
- 将给定对象传递给锁定的上下文assign(_:to:on:)
- 在锁定的上下文中将值存储在对象属性中execute(_:)
- 提供新的锁定上下文orThrow(_:)
- 解包一个 optional,如果为 nil 则抛出指定的错误isNil
/ isNotNil
/ isNilOrEmpty
or()
- 合并别名 (coalescing alias)unwrap()
- 返回解包的 Resultassign(to:on:)
- 通过 keyPath 将封装的值分配给指定的目标属性ifLetAssign(to:on:)
- 如果 optional 不为 nil,则通过 keyPath 将封装的值分配给指定的目标属性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
CoW 容器,允许您递归地包含值类型的单个实例
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!"
基本对象关联助手函数在基础包中可用
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 编译,因此会影响冷编译时间
此包还为 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。
"https://github.com/capturecontext/swift-foundation-extensions.git"
输入到包存储库 URL 文本字段中如果您为您的项目使用 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。