如何在 SwiftUI 的列表项中调用完成处理程序?
Posted
技术标签:
【中文标题】如何在 SwiftUI 的列表项中调用完成处理程序?【英文标题】:How to call completion handler in list item in SwiftUI? 【发布时间】:2021-07-26 16:45:38 【问题描述】:我有一个包含项目的列表,其中还有一个列表。这是列表项:
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, 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)
在这一行:
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,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
【问题讨论】:
@matt,我该如何解决这个问题?也许我们有其他解决方案? 我尝试了 observable obj 但只为几个父列表项下载了数据,所以我认为我做错了 【参考方案1】:首先,我会将您的异步代码移至视图模型。然后,使用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
重构为 one 函数而无需回调 - 您可以看到我已经包装了 usersInCohort
。但是,如果您有兴趣,那只是您可以做的繁琐工作。
最后,我不太确定CohortProcessor
在您的代码中做了什么——它被初始化然后从未使用过。也许该代码应该与我的想法结合起来。
【讨论】:
感谢您的回答,但在添加代码并更正模型导致的所有数据后,我收到了带有 foreach 代码块的此类错误Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project
:(
就像我说的,我没有你所有的代码。我怀疑您需要为ForEach
添加id
。你能用你的ProfilesInCohortModel.ProfilesArrayItem
和UserModel
代码更新你的问题,以便我看看它们是Hashable
还是Identifiable
?
等一下,我加他们
我刚刚添加了它们
尝试用ForEach(retriever.retrievedCohorts.map $0.profile , id: \.id) user in
替换我的ForEach
行以上是关于如何在 SwiftUI 的列表项中调用完成处理程序?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中使用 .refreshable 调用 API 并刷新列表