∙View can conform to Equatable...
True, .equatable() is no longer required, not sure what version that changed in.
.
∙When view contains @ObservedObject...
False, regardless of the outcome of ==, body is always called when any @Published property of the object changes or objectWillChange is published.
.
∙Does view, that is Equatable, need to care about equality of its subviews..
No, a subview will just follow the same algorithm. Best to only init a View with the data it actually needs and uses in its body to keep invalidation tight.
.
∙When view returns true on equality check...
True, if you returned true from == but had @Environment(\.calendar) var calendar and the calendar changed the body would still be called. This is the same behaviour as @ObservedObject in the 2nd question.
.
∙When the observed object conforms to Equatable...
In my testing the if an ObservedObject conformed to Equatable the == func was never called.
My test code:
import SwiftUI
import Combine
struct ViewTest {
class MyObject: ObservableObject, Equatable {
static func == (lhs: ViewTest.MyObject, rhs: ViewTest.MyObject) -> Bool {
// not called
let x = lhs.counter1 == rhs.counter1 && lhs.counter2 == rhs.counter2
return x
}
@Published var counter1 = 0
@Published var counter2 = 0
func inc() {
counter1 += 1
}
}
struct ContentView: View {
@State var counter = 0
@State var counter2 = 0
@StateObject var object = MyObject()
var body: some View {
Form {
Button("Increment \(counter)") {
counter += 1
}
Button("Increment \(counter2)") {
counter2 += 1
}
// ContentView2(x: counter) { [c = counter] in
// print("\(c)") // body is called once when counter2 is changed the first time (once after every time if it has the onReceive
// }
ContentView2(x: counter2)
.environment(\.calendar, ((counter % 2 == 0) ? Calendar.current : Calendar(identifier: .chinese)))
//{
// print("\(self.counter)") // body called every time counter2 is changed
// }
// .equatable()
}
}
}
struct ContentView2: View, Equatable {
// @Environment(\.managedObjectContext) var context
//@State var counter = 0
//@ObservedObject var object: MyObject
@Environment(\.calendar) var calendar
let x: Int
// let y: () -> () // if the closure passed in does somethiung with self then body is always called.
static func == (lhs: Self, rhs: Self) -> Bool {
let result = lhs.x == rhs.x
//&& lhs.object.counter2 == rhs.object.counter2
return result
}
var body: some View {
let _ = Self._printChanges()
HStack {
Text("ff")
Button("Button") {
//y()
}
}
// .onReceive(Just(0)) { _ in // causes body to be called
// print("")
// }
// .task {
// counter = 0
// }.onChange(of: x) { a in
//
// }
// .onAppear {
// counter = 0
// }
}
}
}