SwiftUI列表项中如何调用completion handler并解决ViewBuilder报错
报错原因
Closure containing a declaration cannot be used with result builder 'ViewBuilder'报错的直接原因是你在SwiftUI的body属性(被ViewBuilder结果构造器修饰)内部,声明了一个接收array参数的计算属性usersInCohort。ViewBuilder闭包仅允许构造视图的表达式存在,不允许在内部定义带输入参数的函数/计算属性。
除此之外你的代码还存在3个逻辑问题:
- 同时声明了同名的计算属性和异步请求函数
usersInCohort,存在命名冲突 - 没有对应状态属性存储请求返回的用户列表,请求完成后无法触发视图刷新
- 没有触发异步请求的时机逻辑,父列表项渲染完成后不会自动调用请求接口
修复方案
步骤1:新增状态属性存储用户列表
在CohortItemView中新增@State属性存储接口返回的用户数据,用于刷新子列表:
@State private var userList: [ProfilesInCohortModel.ProfilesArrayItem] = [] @State private var isLoading = false
步骤2:移除body内的非法声明,调整子列表渲染逻辑
把body内的usersInCohort计算属性移除,直接在VStack中写子列表的渲染逻辑,新增onAppear修饰符触发接口请求:
var body: some View { VStack{ HStack{ Text(cohortItem.cohort?.name ?? "no data") .padding(.leading,10) .multilineTextAlignment(.leading) Spacer() ZStack{ Text("Show all \(cohortItem.profilesNum ?? 0)") }.padding(.trailing,10) } // 子列表渲染逻辑 if isLoading { ProgressView() .frame(height: 100) } else if !userList.isEmpty { ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 12){ // 避免数组越界,取前5个元素 ForEach(userList.prefix(5), id: \.profile.id) { item in let user = item.profile UserCard(user: UserModel(name: user.firstName ?? "", position: user.lastName ?? "", image: "moon.stars.fill")) } }.padding(10) } } } // 视图渲染完成后自动触发请求 .onAppear { guard !isLoading else { return } isLoading = true usersInCohort { [weak self] list in DispatchQueue.main.async { self?.isLoading = false self?.userList = list ?? [] } } } }
步骤3:修正异步请求函数的可选值处理
你的请求函数中cohortWebID如果为空会导致请求无效,建议增加空值判断,原有请求逻辑无需额外修改,只需确保回调在主线程赋值即可。
修改完成后,父列表项渲染时会自动触发接口请求,拿到数据后会自动渲染横向滚动的子用户列表,不会再出现编译报错。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

