06iyz
@06iyz

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

画面遷移したらリストが消える

Swift初心者です
初めての開発、質問なので見にくかったらすいません:pray_tone1:

Playgroundsを参考に在庫管理アプリを作ろうとしています。

発生している問題・エラー

![Simulator Screenshot - iPhone 16 Pro - 2024-12-10 at 15.06.28.png] このお風呂というリストをクリックすると、 ![Simulator Screenshot - iPhone 16 Pro - 2024-12-10 at 15.17.03.png] この画面になるようになっています

2枚目の画像の右上プラスボタンを押すとリストを追加できるのですが、
左上の<を押して1枚目の画面に戻ると追加したリストが消えます
何となくどの箇所が原因なのかは分かるのですが、解決の仕方が分かりません

原因と思われる箇所

EventViewでItemViewを表示させるときのItemDataのBinding

ItemView(itemData: ItemData(), event: eventBinding)

どうしたらいいか分からないので下に書いたコード全部載っけてます、、

Event
import SwiftUI

struct Event: Identifiable, Hashable, Codable {
   
    var id = UUID()
    var title = ""
    
    static var delete = Event()
}

EventData
import SwiftUI

class EventData: ObservableObject {
    
    @Published var events: [Event] = [
        
             
        Event(
              title: "お風呂"
              
             ),
        
    ]
    
  
    func add(_ event: Event) {
        events.append(event)
    }
        
    func remove(_ event: Event) {
        events.removeAll { $0.id == event.id}
    }
    
    func getBindingToEvent(_ event: Event) -> Binding<Event>? {
        Binding<Event>(
            get: {
                guard let index = self.events.firstIndex(where: { $0.id == event.id }) else { return Event.delete }
                return self.events[index]
            },
            set: { event in
                guard let index = self.events.firstIndex(where: { $0.id == event.id }) else { return }
                self.events[index] = event
            }
        )
    }
    
}
EventEditor
import SwiftUI

struct EventEditor: View {
    @Binding var event: Event
   
    var body: some View {
        List {
               
                TextField("New List", text: $event.title)
                    .font(.title2)
        }
    }
}
EventRow
import SwiftUI

struct EventRow: View {
    
    @ScaledMetric var imageWidth: CGFloat = 40
    
    let event: Event
    
    var body: some View {
        VStack {
            Label {
                    Text(event.title)
            } icon: {
                Image(systemName: "pencil.circle")
            }
           
        }
        
    }
}
EventView

import SwiftUI

struct EventView: View {
    
    @ObservedObject var eventData: EventData
    @State private var isAddingNewEvent = false
    @State private var isEventEditor = false
    @State private var newEvent = Event()
    @State private var selection: Event?
    
    var body: some View {
        
        NavigationSplitView {
       
                List(selection: $selection) {
                    ForEach(eventData.events) { event in
                        
                        EventRow(event: event)
                            .tag(event)
                        
                            .swipeActions {
                                Button(role: .destructive) {
                                    selection = nil
                                    eventData.remove(event)
                                } label: {
                                    Label("Delete", systemImage: "trash")
                                }
                            }//swipe
                        
                    }//ForEach
                }//List
               
            .toolbar {
                ToolbarItem {
                    Button {
                        newEvent = Event()
                        isAddingNewEvent = true
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
            .sheet(isPresented: $isAddingNewEvent) {
                NavigationStack {
                    EventEditor(event: $newEvent)
                        .toolbar {
                               ToolbarItem(placement: .cancellationAction) {
                                   Button("Cancel") {
                                       isAddingNewEvent = false
                                   }
                               }
                               ToolbarItem {
                                   Button {
                                       eventData.add(newEvent)
                                       isAddingNewEvent = false
                                   } label: {
                                       Text("Add" )
                                   }
                                   .disabled(newEvent.title.isEmpty)
                               }
                            }
                }
            }
           
        
        } detail: {
            ZStack {
                if let event = selection, let eventBinding = eventData.getBindingToEvent(event) {
                    ItemView(itemData: ItemData(), event: eventBinding)
                } else {
                    Text("Select an Event")
                        .foregroundStyle(.secondary)
                }
            }
        }
       
    }
}
Item
import SwiftUI

struct Item: Identifiable, Hashable, Codable {
    
    var id = UUID()
    var title = ""
    var tasks = [Task(text: "", memo: "")]
    
        var remainingTaskCount: Int {
            tasks.filter { !$0.isCompleted && !$0.text.isEmpty }.count
        }
    
        var isComplete: Bool {
            tasks.allSatisfy { $0.isCompleted || $0.text.isEmpty }
        }
       
    static var delete = Item()
 
}


struct NavigationBarBackButtonTextHidden: ViewModifier {
  @Environment(\.presentationMode) var presentaion
  
  func body(content: Content) -> some View {
    content
      .navigationBarBackButtonHidden(true)
      .toolbar {
        ToolbarItem(placement: .navigationBarLeading) {
          Button(action: { presentaion.wrappedValue.dismiss() }) {
            Image(systemName: "chevron.backward")
          }
        }
      }
  }
}

extension View {
  func navigationBarBackButtonTextHidden() -> some View {
    return self.modifier(NavigationBarBackButtonTextHidden())
  }
}
ItemData
import SwiftUI

    class ItemData: ObservableObject {
        
        @Published var items: [Item] = [
            
            
            Item(
                
                title: "洗剤",
                tasks: [Task(text: "マジックリン", memo: "¥305"),]
              
            ),
            
        ]
        
        func add(_ item: Item) {
            items.append(item)
        }
        
        func remove(_ item: Item) {
            items.removeAll { $0.id == item.id}
        }
        
        func getBindingToItem(_ item: Item) -> Binding<Item>? {
            Binding<Item>(
                get: {
                    guard let index = self.items.firstIndex(where: { $0.id == item.id }) else { return Item.delete }
                    return self.items[index]
                },
                set: { item in
                    guard let index = self.items.firstIndex(where: { $0.id == item.id }) else { return }
                    self.items[index] = item
                }
            )
        }
        
       

        
    }
ItemEditor
import SwiftUI

struct ItemEditor: View {
    @Binding var item: Item

    var body: some View {
        NavigationStack {
            List {
                TextField("New List", text: $item.title)
            }
            
            .navigationTitle("新規リスト")
            .navigationBarTitleDisplayMode(.inline)
            
        }
        
    }//var
}//st
ItemRow
import SwiftUI

struct ItemRow: View {
    
    @ScaledMetric var imageWidth: CGFloat = 40
    

    let item: Item
  
    
    var body: some View {
        HStack {
            Label {
                VStack(alignment: .leading, spacing: 5) {
                    Text(item.title)
                    
                }
            } icon: {
                Image(systemName: "pencil.circle")
                
                                        .padding(.trailing, 15)
            }
            
            if item.isComplete {
                Spacer()
                Image(systemName: "xmark.seal")
                    .foregroundStyle(.red)
            }
        }//H
        .badge(item.remainingTaskCount)
    }
}
ItemView
import SwiftUI

struct ItemView: View {
 
    @ObservedObject var itemData: ItemData
    @State private var selection: Item?
    @State private var isShowTaskView = false
    @State private var isShowEditorView = false
    @State private var isShowEditor0 = false
    @State private var newItem = Item()
    @State private var isPickingSymbol = false
    @Binding var event: Event
    
    var body: some View {
        NavigationStack {
            
            List(selection: $selection) {
                ForEach(itemData.items) { item in
                    ItemRow(item: item)
                      
                        .onTapGesture {
                            selection = item
                            isShowTaskView = true
                        }
                        .swipeActions {
                            Button(role: .destructive) {
                                itemData.remove(item)
                            } label: {
                                Label("Delete", systemImage: "trash")
                            }
                            
                            Button {
                                selection = item
                                isShowEditor0 = true
                            } label: {
                                Image(systemName: "pencil.tip.crop.circle.badge.plus")
                            }
                        }
                } // ForEach
            } // List
            
            .sheet(isPresented: $isShowTaskView) {
                NavigationStack {
                    VStack {
                        if let item = selection, let itemBinding = itemData.getBindingToItem(item) {
                            TaskView(item: itemBinding)
                        }
                    }.presentationDetents([.medium])
                    
                        .toolbar {
                           
                                Button {
                                    isShowTaskView = false
                                } label: {
                                    Text("OK")
                                    
                                }
                            
                        }
                }//navi
                   
            }
            
            .sheet(isPresented: $isShowEditor0) {
                NavigationStack {
                    VStack {
                        
                        if let item = selection, let itemBinding = itemData.getBindingToItem(item) {
                            ItemEditor(item: itemBinding)
                        }
                    }
                    
                        .toolbar {
                            
                                Button {
                                    isShowEditor0 = false
                                } label: {
                                    Text("OK" )
                                }
                               
                        }
                }
                   
            }
            
            .toolbar {
                ToolbarItem {
                    Button {
                        newItem = Item()
                        isShowEditorView = true
                    } label: {
                        Image(systemName: "plus.square.on.square")
                    }
                }
                
               
            }//ItemViewのtoolbar
            
         
            
//右上のプラスボタン<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            
            .sheet(isPresented: $isShowEditorView) {
                NavigationStack {
                    ItemEditor(item: $newItem)
                        .toolbar {
                            ToolbarItem {
                                Button {
                                    itemData.add(newItem)
                                    isShowEditorView = false
                                } label: {
                                    Text("Add")
                                }
                                .disabled(newItem.title.isEmpty)
                            }
                            ToolbarItem(placement: .navigationBarLeading) {
                                Button {
                                    isShowEditorView = false
                                } label: {
                                    Text("Cancel")
                                }
                            }
                        }
                }
            }
            
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^右上のプラスボタン
           
        }.navigationBarBackButtonTextHidden()
    }//var
}//st
stock11App
import SwiftUI


@main
struct DatePlannerApp: App {
   
    @StateObject private var eventData = EventData()
    
    
    var body: some Scene {
        WindowGroup {
            
            EventView(eventData: eventData)
            
        }
    }
}
Task
import Foundation

struct Task: Identifiable, Hashable, Codable {
   
    var id = UUID()
    var text: String
    var memo: String
    var isCompleted = false
    var date = Date.now
}

TaskRow


import SwiftUI

struct TaskRow: View {
    @Binding var task: Task
   

    var body: some View {
        HStack {
            Button {
                task.isCompleted.toggle()
            } label: {
                Image(systemName: task.isCompleted ? "checkmark.circle.fill" : "circle")
            }
            .buttonStyle(.plain)
            VStack {
                
                TextField("Task Description", text: $task.text, axis: .vertical)
                TextField("memo", text: $task.memo).font(.subheadline)
            }
         
            Spacer()
            DatePicker("", selection: $task.date, displayedComponents: [.date])
                .environment(\.locale, Locale(identifier: "ja_JP"))
        }
    }
}
TaskView


import SwiftUI

struct TaskView: View {
 @Binding var item: Item

    var body: some View {
        NavigationStack {
            List {
                ForEach($item.tasks) { $task in
                    TaskRow(task: $task)
                }
                
                Button {
                    let newTask = Task(text: "", memo: "¥")
                    item.tasks.append(newTask)
                    
                } label: {
                    HStack {
                        Image(systemName: "plus")
                        Text("Add Task")
                    }
                }//Button
                            
            }   
        }
    }//var
}//st

宜くお願い致します。

0

1Answer

ItemDataクラスがシングルトンになっていないため、クラス生成の度にリストが初期化されるためです。
シングルトンにするために、次の2つのファイルを変更してみてください。

ItemData.swift
- class ItemData: ObservableObject {
+ final class ItemData: ObservableObject {
    
+   public static let shared = ItemData()
+   private init() {}
    
    @Published var items: [Item] = [
EventView.swift
                if let event = selection, let eventBinding = eventData.getBindingToEvent(event) {
-                   ItemView(itemData: ItemData(), event: eventBinding)
+                   ItemView(itemData: ItemData.shared, event: eventBinding)
                } else {

参考

0Like

Your answer might help someone💌