如何在 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
在您的代码中做了什么 -- 它已初始化,但从未使用过。也许那个代码应该结合我的想法。
我有一个列表,其中还有一个列表。这是列表项:
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
在您的代码中做了什么 -- 它已初始化,但从未使用过。也许那个代码应该结合我的想法。