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

How to call completion handler in list item in SwiftUI?

我有一个列表,其中还有一个列表。这是列表项:

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![[=10=]].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, showsIndicators: false) {
                    HStack{
                        ForEach(1..<6, id: \.self) {
                            let user = (array![[=12=]].profile)
                            UserCard(user: UserModel(name: user.firstName ?? "", position: user.lastName ?? "", image: "moon.stars.fill"))
                        }
                    }.padding(10)
                }
            }

在这一行中:

var usersInCohort { array in

我有这样的错误:

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

我不明白为什么 happening.I 尝试使用 also observed object,但它也没有帮助我。因此,我希望在父列表项中看到列表。也许我做错了什么?

更新

我的模特:

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,status,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,akaName,firstName,middleName,lastName,fullName
            case notes,web,wikipedia,twitter,linkedin,instagram,github,phone
            case status,suffix,bio,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"
        }
        
    }
}

和:

struct UserModel {
    var name:String
    var position:String
    var image:String
}

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

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:ForEach.

此外,您可以将 retrieve 重构为 一个 函数而不需要回调——您可以看到我已经包装了 usersInCohort。但是,如果您有兴趣,那只是您可以做的繁琐工作。

最后,我不太确定 CohortProcessor 在您的代码中做了什么 -- 它已初始化,但从未使用过。也许那个代码应该结合我的想法。