Created
May 25, 2018 12:01
-
-
Save Moximillian/6ec7e2d2e5b12c1bce0d09b7faa51ee2 to your computer and use it in GitHub Desktop.
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
import Foundation | |
extension NSObjectProtocol where Self: NSObject { | |
internal func store(associatedObject: Any) { | |
// store the container so that it can be called later, we do not need to explicitly retrieve it. | |
var associatedObjectStore = objc_getAssociatedObject(self, Unmanaged.passUnretained(self).toOpaque()) as? [Any] ?? [] | |
associatedObjectStore.append(associatedObject) | |
objc_setAssociatedObject(self, Unmanaged.passUnretained(self).toOpaque(), associatedObjectStore, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
} | |
class Disposable { | |
typealias ClosureType = () -> Void | |
let closure: ClosureType | |
init(_ closure: @escaping ClosureType) { | |
self.closure = closure | |
} | |
deinit { | |
print("Disposable.\(#function)") | |
closure() | |
} | |
} | |
extension NSObjectProtocol where Self: NSObject { | |
func observe<Value>(_ keyPath: KeyPath<Self, Value>, onChange: @escaping (Value) -> ()) -> Disposable { | |
let observation = observe(keyPath, options: [.initial, .new]) { _, change in | |
// The guard is because of https://bugs.swift.org/browse/SR-6066 | |
guard let newValue = change.newValue else { return } | |
onChange(newValue) | |
} | |
return Disposable { observation.invalidate() } | |
} | |
public func bind<Value, Target: NSObject>(_ sourceKeyPath: KeyPath<Self, Value>, to target: Target, at targetKeyPath: ReferenceWritableKeyPath<Target, Value>) { | |
let disposable = observe(sourceKeyPath) { [weak target] in | |
target?[keyPath: targetKeyPath] = $0 } | |
target.store(associatedObject: disposable) | |
} | |
} | |
final class Foo: NSObject { | |
@objc dynamic var bar: Int = 0 { | |
didSet { | |
print("Bar changed to: \(bar)") | |
} | |
} | |
} | |
final class Zoq: NSObject { | |
var fot: Int = 0 { | |
didSet { | |
print("fot changed to: \(fot)") | |
} | |
} | |
deinit { | |
print("Zoq.\(#function)") | |
} | |
} | |
let foo = Foo() | |
var zoq = Zoq() | |
foo.bar = 42 | |
foo.bind(\.bar, to: zoq, at: \.fot) | |
foo.bar = 2 | |
zoq = Zoq() // Zoq.deinit, Disposable.deinit | |
foo.bar = 4 | |
zoq.fot | |
foo.bar = 8 | |
zoq.fot | |
foo.bar = 12 | |
zoq.fot |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment