Last active
February 15, 2022 13:02
-
-
Save bocato/dd8929873d18bddaf3fe90acc6341ea6 to your computer and use it in GitHub Desktop.
Implements @Environment, but for UIKit stuff.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Implementation | |
public protocol UIKitEnvironmentKey { | |
associatedtype Value | |
static var defaultValue: Value { get } | |
} | |
public struct UIKitEnvironmentValues: CustomStringConvertible { | |
private class Wrapper { | |
init() {} | |
var value: Any? | |
} | |
public var description: String { .init(describing: wrapper.value) } | |
private var wrapper: Wrapper = .init() | |
public init() {} // Should not me intialized outside of an @UIKitEnvironment | |
public subscript<K>(key: K.Type) -> K.Value where K: UIKitEnvironmentKey { | |
get { wrapper.value as? K.Value ?? K.defaultValue } | |
set { wrapper.value = newValue } | |
} | |
mutating func update<V>(_ keypath: WritableKeyPath<UIKitEnvironmentValues, V>, _ newValue: V) { // fileprivate? | |
self[keyPath: keypath] = newValue | |
} | |
} | |
@frozen @propertyWrapper public struct UIKitEnvironment<Value> { | |
public var values: UIKitEnvironmentValues = .init() | |
public let keyPath: KeyPath<UIKitEnvironmentValues, Value> | |
@inlinable public init(_ keyPath: KeyPath<UIKitEnvironmentValues, Value>) { | |
self.keyPath = keyPath | |
} | |
@inlinable public var wrappedValue: Value { values[keyPath: keyPath] } | |
} | |
public protocol UKitEnviromentSetter {} | |
extension UKitEnviromentSetter { | |
public func uikitEnvironment<V>(_ keypath: WritableKeyPath<UIKitEnvironmentValues, V>, _ newValue: V) -> Self { | |
let mirror = Mirror(reflecting: self) | |
var uiKitEnvironment = mirror | |
.children | |
.first(where: { $0.value is UIKitEnvironment<V> })? | |
.value as? UIKitEnvironment<V> | |
uiKitEnvironment?.values.update(keypath, newValue) | |
return self | |
} | |
} | |
extension UIViewController: UKitEnviromentSetter {} | |
extension UIView: UKitEnviromentSetter {} | |
// Usage | |
private struct UIKitStringContainerEnvironmentKey: UIKitEnvironmentKey { | |
static let defaultValue: String = "defaultValue" | |
} | |
public extension UIKitEnvironmentValues { | |
var stringValue: String { | |
get { self[UIKitStringContainerEnvironmentKey.self] } | |
set { self[UIKitStringContainerEnvironmentKey.self] = newValue } | |
} | |
} | |
import UIKit | |
import SwiftUI | |
class ViewController2: UIViewController { | |
@UIKitEnvironment(\.stringValue) var stringValue: String | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
let button = UIButton(configuration: .gray(), primaryAction: .init(handler: { action in | |
print(self.stringValue) | |
})) | |
button.frame = .init(x: view.center.x, y: view.center.y, width: 50, height: 50) | |
self.view.addSubview(button) | |
self.view.backgroundColor = .blue | |
} | |
} | |
class ViewController: UIViewController { | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
let button = UIButton(configuration: .filled(), primaryAction: .init(handler: { action in | |
let newController = ViewController2() | |
.uikitEnvironment(\.stringValue, "Not Default!") | |
self.present(newController, animated: true, completion: nil) | |
})) | |
button.frame = .init(x: view.center.x, y: view.center.y, width: 100, height: 100) | |
self.view.addSubview(button) | |
self.view.backgroundColor = .red | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment