In the following code, I have an optional @State variable call isReseting which I set to true with a tap of a button. The button also triggers a sheet when it's tapped, which is working fine but what doesn't work is that if I read the value of the isResting variable inside the .sheet it outputs as nil and I'm expecting that to be true since it was set to true when the button was tapped.
Any idea why the value of the isReseting variable becomes nil inside the .sheet?
struct Item: Identifiable{
var id = UUID()
var name:String
var active:Bool
}
struct ContentView: View {
var items:[Item] = [Item(name: "Oranges", active: true),
Item(name: "Apples", active: false),
Item(name: "Cookies", active: false) ]
@State private var selectedItem: Item?
@State private var isReseting: Bool?
var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)
Button(item.active ? "Reset": "Initiate"){
selectedItem = item
isReseting = true
let _ = print("Value after button tap: \(isReseting)")// output: Value after button tap: Optional(true)
}
.padding()
.background(item.active ? Color.blue: Color.gray)
.foregroundColor(.white)
.cornerRadius(30)
.frame(width: 100, height: 65)
}
}
}
.sheet(item: $selectedItem){ item in
// I'm expecting isReseting to be true here, but it's nil
let _ = print("Value in sheet: \(isReseting)")// outputs: Value in sheet: nil
if isReseting == true {
Text("It's reseting!!!")
}else{
Text("It's NOT reseting")
}
}
}
}
CodePudding user response:
I think you're getting caught by the fact that sheet(item:) only re-renders based on item -- not the encapsulating View's @State variables. As long as you explicitly pass isReseting through the item, it will work:
struct Item: Identifiable, Equatable {
var id = UUID()
var name:String
var active:Bool
}
struct ContentView: View {
var items:[Item] = [Item(name: "Oranges", active: true),
Item(name: "Apples", active: false),
Item(name: "Cookies", active: false) ]
struct SheetItem : Identifiable {
var item: Item
var isReseting: Bool
var id: UUID {
self.item.id
}
}
@State private var selectedItem: SheetItem?
@State private var isReseting: Bool?
var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)
Button(item.active ? "Reset": "Initiate"){
isReseting = true
selectedItem = SheetItem(item: item, isReseting: isReseting ?? false)
}
.padding()
.background(item.active ? Color.blue: Color.gray)
.foregroundColor(.white)
.cornerRadius(30)
.frame(width: 100, height: 65)
}
}
}
.sheet(item: $selectedItem) { item in
let _ = print("Value in sheet: \(item.isReseting)")
if item.isReseting == true {
Text("It's reseting!!!")
} else {
Text("It's NOT reseting")
}
}
}
}
A second way to accomplish this is explicitly pass a Binding (even though you don't need to mutate it in the sheet), since it will maintain its link to the @State variable:
struct Item: Identifiable{
var id = UUID()
var name:String
var active:Bool
}
struct ContentView: View {
var items:[Item] = [Item(name: "Oranges", active: true),
Item(name: "Apples", active: false),
Item(name: "Cookies", active: false) ]
@State private var selectedItem: Item?
@State private var isReseting: Bool?
var body: some View {
List{
ForEach(items){ item in
HStack{
Text(item.name)
Button(item.active ? "Reset": "Initiate"){
selectedItem = item
isReseting = true
let _ = print("Value after button tap: \(isReseting)")// output: Value after button tap: Optional(true)
}
.padding()
.background(item.active ? Color.blue: Color.gray)
.foregroundColor(.white)
.cornerRadius(30)
.frame(width: 100, height: 65)
}
}
}
.sheet(item: $selectedItem){ item in
// I'm expecting isReseting to be true here, but it's nil
SheetView(isReseting: $isReseting)
}
}
}
struct SheetView : View {
@Binding var isReseting : Bool?
var body: some View {
let _ = print("Value in sheet: \(isReseting)")// outputs: Value in sheet: nil
if isReseting == true {
Text("It's reseting!!!")
}else{
Text("It's NOT reseting")
}
}
}
