I have a watchOS app which has two screens. When I navigate to the second screen I get the following warning in the console:
ScrollView contentOffset binding has been read; this will cause grossly inefficient view performance as the ScrollView's content will be updated whenever its contentOffset changes. Read the contentOffset binding in a view that is not parented between the creator of the binding and the ScrollView to avoid this.
This seems to be related to using the @EnvironmentObject for the picker selection in the second screen. The warning does not happen if I remove the @EnvironmentObject and replace it with @State for the picker selection. (But then the updates are not reflected on the first screen).
Why is this happening? What can I do to stop this warning?
Here is my code:
First screen:
import SwiftUI
struct ContentView: View {
@EnvironmentObject var itemManager: ItemManager
var body: some View {
List {
ForEach(itemManager.items.indices) { index in
NavigationLink(destination: ItemView(index: index)) {
VStack(alignment: HorizontalAlignment.leading) {
HStack {
Text(self.itemManager.items[index].name)
Spacer()
Text("x")
Text(String(self.itemManager.items[index].quantity))
}
Text(self.itemManager.items[index].type.rawValue).font(.footnote)
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(ItemManager())
}
}
Second screen:
import SwiftUI
struct ItemView: View {
@EnvironmentObject var itemManager: ItemManager
var index: Int
var body: some View {
VStack {
Text("Update")
Form {
Section {
Picker(selection: $itemManager.items[index].type, label: Text("Food Type")) {
ForEach(FoodType.allCases.sorted()) { type in
Text(type.rawValue).tag(type)
}
}
}
}
}.navigationBarTitle(Text("Item"))
}
}
struct ItemView_Previews: PreviewProvider {
static var previews: some View {
return ItemView(index: 0).environmentObject(ItemManager())
}
}
Model:
import Foundation
enum FoodType: String, CaseIterable, Identifiable, Comparable{
case fruit
case vegetable
case poultry
case bakery
var id: FoodType{self}
static func < (lhs: FoodType, rhs: FoodType) -> Bool {
lhs.rawValue < rhs.rawValue
}
}
struct Item {
var type: FoodType
var quantity: Int
var name: String
}
class ItemManager: ObservableObject {
@Published var items: [Item] =
[
Item(type: FoodType.fruit, quantity: 1, name: "apple"),
Item(type: FoodType.bakery, quantity: 1, name: "french bread"),
Item(type: FoodType.vegetable, quantity: 6, name: "carrots")
]
}
HostingController:
import WatchKit
import Foundation
import SwiftUI
class HostingController: WKHostingController<AnyView> {
override var body: AnyView {
return AnyView(ContentView()
.environmentObject(ItemManager()))
}
}