Skip to content

Instantly share code, notes, and snippets.

@muukii
Created April 27, 2021 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muukii/99f1567de067f500c9bd68563c3d9c8d to your computer and use it in GitHub Desktop.
Save muukii/99f1567de067f500c9bd68563c3d9c8d to your computer and use it in GitHub Desktop.
//: [Previous](@previous)
import Foundation
final class FilterStorage {
private var storage: [String: Any] = [:]
func comparer<T>(for key: String) -> ((T) -> Bool)? {
guard let object = storage[key] else {
return nil
}
return object as? ((T) -> Bool)
}
func setComaprer<T>(_ comparer: @escaping (T) -> Bool, for key: String) {
storage[key] = comparer
}
}
func _doIfChanged<T>(
usingStorage: FilterStorage,
key: String,
value: T,
compare: @escaping (T, T) -> Bool,
perform: @escaping (T) -> Void
) {
defer {
let nextIsEqual: (T) -> Bool = { newValue in
compare(value, newValue)
}
usingStorage.setComaprer(nextIsEqual, for: key)
}
guard let isEqual: (T) -> Bool = usingStorage.comparer(for: key) else {
perform(value)
return
}
guard isEqual(value) == false else {
return
}
perform(value)
}
private var _storageKey: Void?
extension NSObject {
private var storage: FilterStorage {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if let associated = objc_getAssociatedObject(self, &_storageKey)
as? FilterStorage
{
return associated
} else {
let associated = FilterStorage()
objc_setAssociatedObject(self, &_storageKey, associated, .OBJC_ASSOCIATION_RETAIN)
return associated
}
}
public func doIfChanged<T>(
file: StaticString = #file,
line: UInt = #line,
column: UInt = #column,
value: T,
compare: @escaping (T, T) -> Bool,
perform: @escaping (T) -> Void
) {
let key = "\(column).\(line).\(file)"
_doIfChanged(
usingStorage: storage,
key: key,
value: value,
compare: compare,
perform: perform
)
}
public func doIfChanged<T: Equatable>(
file: StaticString = #file,
line: UInt = #line,
column: UInt = #column,
value: T,
perform: @escaping (T) -> Void
) {
let key = "\(column).\(line).\(file)"
_doIfChanged(
usingStorage: storage,
key: key,
value: value,
compare: ==,
perform: perform
)
}
}
import UIKit
class MyView: UIView {
func run(value: Int) {
view.doIfChanged(value: value) { v in
print("😲 \(value)")
}
}
}
let view = MyView()
view.run(value: 1)
view.run(value: 2)
view.run(value: 2)
//: [Next](@next)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment