0

well so the problem: when i open the EditViewScreen i need to get the title(-text) and body(-text) of that post. But I always get the title and body of the first cell.

then I didn’t understand the meaning of this post either: 2022-06-03 06:52:57.858609+0500 SwiftuiMVVM[4334:105229] [Presentation] Attempt to present <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x127e734d0> on <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x127e0ac70> (from <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentGS1_VVS_22_VariadicView_Children7ElementVS_24NavigationColumnModifier_GVS_18StyleContextWriterVS_19SidebarStyleContext__: 0x127e12bc0>) which is already presenting <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x12a604820>.

HomeViewScreen()

            ZStack {
                List {
                    ForEach(viewModel.posts, id: \.self) { post in
                        PostCell(post: post).onLongPressGesture {
                            showingEdit.toggle()
                        }.sheet(isPresented: $showingEdit) {
                            EditViewScreen(post: post)
                        }
                    }
                    .onDelete(perform: delete)
                }.listStyle(.plain)
                if viewModel.isLoading {
                    ProgressView()
                }
            }

EditViewScreen()

import SwiftUI

struct EditViewScreen: View {
    @ObservedObject var viewModel = EditViewModel()
    @Environment(\.presentationMode) var presentation
    
    var post: Post    
    
    @State var p_title = ""
    @State var p_body = ""
    
    func updatePost() {
        let post = Post(id: post.id!, title: p_title, body: p_body)
        viewModel.apiPostUpdate(post: post, handler: { isUpdated in
            if isUpdated {
                presentation.wrappedValue.dismiss()
            }
        })
    }
    
    var body: some View {
        NavigationView {
            ZStack {
                VStack(spacing: 10) {
                    TextField("Edit title", text: $p_title)
                        .frame(height: 60)
                        .padding(.leading)
                        .background(.gray.opacity(0.1))
                        .cornerRadius(10)
                        .font(.system(size: 18))
                    TextField("Edit body", text: $p_body)
                        .frame(height: 60)
                        .padding(.leading)
                        .background(.gray.opacity(0.1))
                        .cornerRadius(10)
                        .font(.system(size: 18))
                    
                    Button(action: {
                        updatePost()
                    }, label: {
                        Spacer()
                        Text("Update")
                        Spacer()
                    })
                    .padding()
                    .frame(height: 60)
                    .background(.black.opacity(0.7))
                    .foregroundColor(.white)
                    .cornerRadius(10)
                    .font(.system(size: 18))
                    
                    Spacer()
                }
                .padding(.leading)
                .padding(.trailing)
                .padding(.top, -35)
                
                if viewModel.isLoading {
                    ProgressView()
                }
            }

            .navigationBarItems(leading: Button(action: {
                presentation.wrappedValue.dismiss()
            }, label: {
                Text("Cancel")
                    .foregroundColor(.black)
                    .font(.system(size: 18, weight: .light))
            }))
        }.onAppear {
            p_title = post.title!
            p_body = post.body!
        }
        
        
    }
}

2 Answers2

1

Well, some shortcomings have passed. I've made changes to the HomeViewModel().

class HomeViewModel: ObservableObject {
    @Published var isLoading = false
    @Published var posts = [Post]()

    @Published var post = Post() // <-- here
    
    func apiPostList() {
        isLoading = true
        AFHttp.get(url: AFHttp.API_POST_LIST, params: AFHttp.paramsEmpty(), handler: { response in
            self.isLoading = false
            
            switch response.result {
            case .success:
                let posts = try! JSONDecoder().decode([Post].self, from: response.data!)
                self.posts =  posts
            case let .failure(error):
                print(error)
            }
        })
    }
}

HomeViewScreen()

struct HomeViewScreen: View {
    @ObservedObject var viewModel = HomeViewModel()
    @State private var showingEdit = false
    
    var body: some View {
        NavigationView {
            ZStack {
                List {
                    ForEach(viewModel.posts, id: \.self) { post in
                        PostCell(post: post)
                            .onLongPressGesture {
                                showingEdit.toggle()
                                viewModel.post = post   // <-- here
                            }.sheet(isPresented: $showingEdit) {
                                EditViewScreen(post: viewModel.post)  
                              // 'll be viewmodel.post, not just the post itself
                        }
                    }
                    .onDelete(perform: delete)
                }
                .listStyle(.plain)
                
                if viewModel.isLoading {
                    ProgressView()
                }
            }

Thank you for your attention(awa @workingdog)

0

try this approach using @StateObject var viewModel in your HomeViewScreen, and passing that to EditViewScreen. In addition use .sheet(item: ...) outside the ForEach loop, as in the example code. Importantly never use forced unwrapping, that is, do not use ! in your code at all, use if let ... or guard ....

struct HomeViewScreen: View {
    @StateObject var viewModel = EditViewModel() // <-- here
    @State var selectedPost: Post? // <-- here
    
    var body: some View {
        ZStack {
            List {
                ForEach(viewModel.posts, id: \.self) { post in
                    PostCell(post: post).onLongPressGesture {
                        selectedPost = post  // <-- here
                    }
                }
                .onDelete(perform: delete)
            }.listStyle(.plain)
            
            // -- here
            .sheet(item: $selectedPost) { post in
                EditViewScreen(post: post, viewModel: viewModel) // <-- here
            }
            
            if viewModel.isLoading {
                ProgressView()
            }
        }
    }
}

struct EditViewScreen: View {
    @ObservedObject var viewModel: EditViewModel  // <-- here
    @Environment(\.presentationMode) var presentation
    
    var post: Post
    
    @State var p_title = ""
    @State var p_body = ""
    
//....