Skip to content

Instantly share code, notes, and snippets.

@malhal
Last active October 28, 2024 20:36
Show Gist options
  • Save malhal/55d35ee4108973c96b05be7e23c39add to your computer and use it in GitHub Desktop.
Save malhal/55d35ee4108973c96b05be7e23c39add to your computer and use it in GitHub Desktop.
Cached sort
import SwiftUI
@Observable
class Counter: Identifiable {
var count = 0
}
@Observable
class Model {
var counters: [Counter] = [.init(), .init(), .init()]
}
@Observable
class SortedModel {
@ObservationIgnored
var model: Model! {
didSet {
if oldValue !== model {
_counters = nil
}
}
}
var ascending = false
var _counters: [Counter]?
var counters: [Counter] {
if _counters == nil {
_counters = withObservationTracking {
// tracks self.ascending and model.counters.counts
let sort = SortDescriptor(\Counter.count, order: ascending ? .forward : .reverse)
return model.counters.sorted(using: sort)
} onChange: { [weak self] in
self?._counters = nil
}
}
return _counters!
}
}
struct ContentView: View {
@State var model: Model?
@State var callBody = 0
var body: some View {
NavigationStack {
if let model {
Button("Call body \(callBody)") {
callBody += 1
}
Button("Add Counter") {
model.counters.append(.init())
}
Button("New Model") {
self.model = Model()
}
HStack {
CounterView(x: callBody, model: model)
CounterView(x: callBody, model: model)
}
}
}
.onAppear {
model = Model()
}
}
}
struct CounterView: View {
let x: Int
let model: Model
@State var sortedModel: SortedModel?
var body: some View {
List {
if let sortedModel {
let _ = sortedModel.model = model
Button(sortedModel.ascending ? "Ascending" : "Descending") {
withAnimation {
sortedModel.ascending.toggle()
}
}
ForEach(sortedModel.counters) { c in
Button("\(c.count, format: .number)") {
withAnimation {
c.count += 1
}
}
}
}
}
.onAppear {
sortedModel = SortedModel()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment