Skip to content

Instantly share code, notes, and snippets.

@MaximKotliar
Last active February 13, 2020 12:17
Show Gist options
  • Save MaximKotliar/dff0b195e910196270125869a3ad5b0e to your computer and use it in GitHub Desktop.
Save MaximKotliar/dff0b195e910196270125869a3ad5b0e to your computer and use it in GitHub Desktop.
//
// KeyPathBasedConfiguration.swift
//
// Created by Maxim Kotliar on 13.02.2020.
// Copyright © 2020 Wikrgroup. All rights reserved.
//
import Foundation
@dynamicMemberLookup
struct KeyPathBasedConfiguration<Base: AnyObject> {
struct KeyPathConfig {
fileprivate let keyPath: PartialKeyPath<Base>
fileprivate let value: Any
fileprivate let apply: ((Base) -> Void)
init<T>(_ keyPath: ReferenceWritableKeyPath<Base, T>, _ value: T) {
self.keyPath = keyPath
self.value = value
self.apply = { $0[keyPath: keyPath] = value }
}
}
init(_ keyPathConfigurations: [KeyPathConfig]) {
var configs: [AnyKeyPath: KeyPathConfig] = [:]
for config in keyPathConfigurations {
configs[config.keyPath] = config
}
self.configurations = configs
}
private var configurations: [AnyKeyPath: KeyPathConfig]
subscript <T>(dynamicMember keyPath: ReferenceWritableKeyPath<Base, T>) -> T? {
get {
configurations[keyPath]?.value as? T
}
set {
guard let newValue = newValue else {
configurations[keyPath] = nil
return
}
configurations[keyPath] = .init(keyPath, newValue)
}
}
func apply(to base: Base, ignoring: Set<PartialKeyPath<Base>>) {
for (_, config) in configurations {
guard !ignoring.contains(config.keyPath) else { continue }
config.apply(base)
}
}
}
// Example
import UIKit
extension UINavigationItem {
typealias NavigationBarConfiguration = KeyPathBasedConfiguration<UINavigationBar>
}
extension UINavigationItem.NavigationBarConfiguration {
static let `default` = UINavigationItem.NavigationBarConfiguration([.init(\.isHidden, false),
.init(\.isTranslucent, true),
.init(\.backgroundColor, .clear),
.init(\.tintColor, .white)])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment