如何在 SwiftUI 的列表项中调用完成处理程序?

问题描述

我有一个包含项目的列表,其中还有一个列表。这是列表项:

openxlsx::write.xlsx(df1,'yourfile.xlsx',keepNA = TRUE)

如您所见,我在列表项中有列表。我想在显示列表项后显示列表。这是这个子列表项:

struct CohortItemView:View {
    @State var cohortsGetter: ProfilesInCohort
    let cohortItem:CohortArrayItem
    @Observedobject var profilesGetter = CohortProcessor()
    
    init(item:CohortArrayItem) {
        self.cohortItem = item
        self.cohortsGetter = ProfilesInCohort.init(cohortWebId: cohortItem.cohort?.webID ?? "")
    }
    
    var body: some View {
        vstack{
            HStack{
                Text(cohortItem.cohort?.name ?? "no data")
                    .padding(.leading,10)
                    .multilineTextAlignment(.leading)
                Spacer()
                
                ZStack{
                    Text("Show all \(cohortItem.profilesNum!)")
                }.padding(.trailing,10)
            }
            
            
            var usersInCohort { array in
                ScrollView(.horizontal,showsIndicators: false) {
                    HStack{
                        ForEach(1..<6,id: \.self) {
                            let user = (array![$0].profile)
                            UserCard(user: usermodel(name: user.firstName ?? "",position: user.lastName ?? "",image: "moon.stars.fill"))
                        }
                    }.padding(10)
                }
            }
            
        }
    }
    
    func usersInCohort(completion:@escaping ([ProfilesInCohortModel.ProfilesArrayItem]?)->Void) {
        let params = ["offset":6,"cohortWebID":cohortItem.cohort?.webID ?? ""] as [String : Any]
        
        var request = URLRequest(url: URL(string: "url")!)
        request.httpMethod = HTTPMethod.post.rawValue
        request.httpBody =  try? JSONSerialization.data(withJSONObject: params,options: [])
        request.setValue("application/json; charset=UTF-8",forHTTPHeaderField: "Content-Type")
        
        
        AF.request(request).responseDecodable(of: ProfilesInCohortModel.self) { (response) in
            if response.response?.statusCode == 200{
                completion(response.value?.profiles)
            }
        }
    }
}

但是在这代码块中:

struct UserCard: View {
    let user:usermodel
    init(user:usermodel) {
        self.user = user
    }
    var body: some View {
        vstack{
            ZStack(alignment: .topTrailing) {
                Image(systemName: user.image)
                    .resizable()
                    .frame(width: 64.0,height: 64.0)
                    .clipShape(Circle())
                    .shadow(radius: 10)
                Button(action: {
                    print("Edit button was tapped")
                }) {
                    Image(systemName: user.image)
                }
            }
            Text(user.name)
                .fontWeight(.regular)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
            Text(user.position)
                .foregroundColor(.gray)
                .multilineTextAlignment(.center)
        }
        .background(Color.green)
    }
}

在这一行:

var usersInCohort { array in
                ScrollView(.horizontal,image: "moon.stars.fill"))
                        }
                    }.padding(10)
                }
            }

我有这样的错误

var usersInCohort { array in

我不明白为什么会这样。我也尝试使用观察到的对象,但它也没有帮助我。因此,我想在父列表项中看到列表。也许我做错了?

更新

我的模型:

Closure containing a declaration cannot be used with result builder 'viewbuilder'

和:

struct ProfilesInCohortModel:Decodable {
    var num,status:Int?
    var noMore,authrequired:Bool?
    var profiles:[ProfilesArrayItem]?
    
    enum CodingKeys:String,CodingKey {
        case num,status,authrequired,profiles
        case noMore = "flagNoMore"
    }
    
    
    struct ProfilesArrayItem:Decodable{
        let profile:ProfileItem
        let publiclyForwarded:Int
        let altCohort:CohortItem
        
        enum CodingKeys:String,CodingKey {
            case profile,altCohort
            case publiclyForwarded = "followedBySessionUser_publicly"
        }
    }
    
    struct ProfileItem:Decodable,Identifiable {
        let id = UUID()
        let inode,superSedByNode,createdUser,editedUser:Int?
        let webID,notes,web,wikipedia,suffix,bio,title:String?
        let name,akaName,firstName,middleName,lastName,fullName:String?
        let twitter,linkedin,instagram,github,email,phone:String?
        let createTime,lastEditTime:UInt64?
        let hasImage:Bool?
        
        enum CodingKeys:String,CodingKey {
            case inode,webID,name,fullName
            case notes,twitter,phone
            case status,title
            case editedUser = "user_lastedit"
            case createdUser = "user_created"
            case superSedByNode = "superseded_by_node"
            case email = "contact_email"
            case createTime = "time_created"
            case lastEditTime = "time_lastedit"
            case hasImage =  "has_image"
        }
        
    }
}

解决方法

首先,我会将您的异步代码移至视图模型。然后,使用 onAppear 调用异步方法来检索同类群组。然后,您可以对存储在 ForEach 变量中的结果使用 Published

class CohortRetriever : ObservableObject {
    @Published var retrievedCohorts: [ProfilesInCohortModel.ProfilesArrayItem] = []
    
    func retrieve(cohortItem: CohortArrayItem) {
        self.usersInCohort(cohortItem: cohortItem) { result in
            self.retrievedCohorts = result
        }
    }
    
    private func usersInCohort(cohortItem: CohortArrayItem,completion:@escaping ([ProfilesInCohortModel.ProfilesArrayItem]?)->Void) {
        let params = ["offset":6,"cohortWebID":cohortItem.cohort?.webID ?? ""] as [String : Any]
        
        var request = URLRequest(url: URL(string: "url")!)
        request.httpMethod = HTTPMethod.post.rawValue
        request.httpBody =  try? JSONSerialization.data(withJSONObject: params,options: [])
        request.setValue("application/json; charset=UTF-8",forHTTPHeaderField: "Content-Type")
        
        
        AF.request(request).responseDecodable(of: ProfilesInCohortModel.self) { (response) in
            if response.response?.statusCode == 200{
                completion(response.value?.profiles)
            }
        }
    }
}

struct CohortItemView:View {
    @State var cohortsGetter: ProfilesInCohort
    let cohortItem:CohortArrayItem
    @ObservedObject var profilesGetter = CohortProcessor()
    
    @StateObject var retriever = CohortRetriever()
    
    init(item:CohortArrayItem) {
        self.cohortItem = item
        self.cohortsGetter = ProfilesInCohort.init(cohortWebId: cohortItem.cohort?.webID ?? "")
    }
    
    var body: some View {
        VStack{
            HStack{
                Text(cohortItem.cohort?.name ?? "no data")
                    .padding(.leading,10)
                    .multilineTextAlignment(.leading)
                Spacer()
                
                ZStack{
                    Text("Show all \(cohortItem.profilesNum!)")
                }.padding(.trailing,10)
            }
            
            ScrollView(.horizontal,showsIndicators: false) {
                HStack{
                    ForEach(retriever.retrievedCohorts) { user in //<-- Here
                        UserCard(user: UserModel(name: user.firstName ?? "",position: user.lastName ?? "",image: "moon.stars.fill"))
                    }
                }.padding(10)
            }
        }.onAppear { //<-- Here
            self.retriever.retrieve(cohortItem: cohortItem)
        }
    }
}

请注意,我没有您的所有代码,因此可能存在一些小问题,例如,如果您的模型不符合 Hashable,您可能需要将 id: 传递给 { {1}}。

此外,您可以将 ForEach 重构为 one 函数而无需回调——您可以看到我已经包装了 retrieve。但是,如果您有兴趣,这只是您可以做的繁忙工作。

最后,我不太确定 usersInCohort 在您的代码中做了什么——它被初始化,然后从未使用过。也许那个代码应该和我的想法结合起来。