我正在尝试在我的swift应用中遍历对象字典并将它们显示在列表中。我不断收到错误消息,类型'[Note]'的值没有成员'prettyUpdatedString'。我在哪里错了?
更新:由于社区成员的输入,我已经能够编译代码,但是数据仍未显示在列表中。没有引发任何错误,但该区域只是空白。参见屏幕截图。
数据:
[
{
id: 2867,
type: "TechNote",
isSolution: false,
prettyUpdatedString: "1 day ago <strong>Cody Brown</strong> said",
mobileNoteText: "Attempted contact, left voicemail no anwser.",
isTechNote: true,
isHidden: false,
workTime: "0"
},
{
id: 2863,
type: "TechNote",
isSolution: true,
prettyUpdatedString: "1 day ago <strong>Cody Brown</strong> said",
mobileNoteText: "Computer is repaired and ready to be picked up. Please come to the High School Wednesdays (1pm-2pm). If you have a loaner computer please bring it along with the the student.",
isTechNote: true,
isHidden: false,
workTime: "0"
},
{
id: 2818,
type: "TechNote",
isSolution: false,
prettyUpdatedString: "2 weeks ago <strong>Cody Brown</strong> said",
mobileNoteText: "Sent to AGI for repair.",
isTechNote: true,
isHidden: false,
workTime: "0"
},
{
id: 2814,
type: "TechNote",
isSolution: false,
prettyUpdatedString: "2 weeks ago <strong>Cody Brown</strong> said",
mobileNoteText: "Brought to Office",
isTechNote: true,
isHidden: false,
workTime: "0"
},
{
id: 2790,
type: "TechNote",
isSolution: false,
prettyUpdatedString: "2 weeks ago <strong>Seth Duncan</strong> said",
mobileNoteText: "Left VM",
isTechNote: true,
isHidden: true,
workTime: "0"
},
{
id: 2717,
type: "TechNote",
isSolution: false,
prettyUpdatedString: "2 weeks ago <strong>Seth Duncan</strong> said",
mobileNoteText: "<br/> We will be at the OHS Front Office from 1-2PM on Wednesdays to assist with computer issues",
isTechNote: true,
isHidden: false,
workTime: "0"
}
]
获取数据
import SwiftUI
struct Note: Decodable, Identifiable {
var id: Int
var prettyUpdatedString: String
var mobileNoteText: String
}
class FetchTicketNotes: ObservableObject {
func getTicketNotes(id: Int, userApi: String, completion: @escaping ([Note]) -> ()) {
guard let url = URL(string: "URL HERE") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
let ticketNotes = try! JSONDecoder().decode([Note].self, from: data!)
DispatchQueue.main.async {
completion(ticketNotes)
}
}
.resume()
}
}
在视图中
import SwiftUI
struct DetailsView: View {
@ObservedObject var ticketStatusAction = TicketStatusAction()
@ObservedObject var createTicketNote = CreateTicketNote()
@State var ticket: [TicketDetails] = []
@State var ticketNotes: [Note] = []
@State private var showingNoteAlert = false
@State private var showingOpenAlert = false
@State private var showingPendingAlert = false
@State private var showingDepotAlert = false
@State private var showingCloseAlert = false
@State private var note: String = ""
@ObservedObject private var keyboard = KeyboardResponder()
var id: Int
var displayClient: String
@Binding var userApi: String
var body: some View {
ScrollView(.vertical, showsIndicators: false){
VStack(alignment: .leading){
if !ticket.isEmpty {
Text(self.ticket.first?.location.locationName ?? "")
.fontWeight(.bold)
.padding()
}
Text("\(displayClient) - \(id)")
.fontWeight(.bold)
.font(.system(size:20))
.padding()
Divider()
Text("Status")
.fontWeight(.bold)
.padding()
if !ticket.isEmpty {
Text(self.ticket.first?.statustype.statusTypeName ?? "")
.padding()
}
Text("Details")
.fontWeight(.bold)
.padding()
if !ticket.isEmpty {
Text(clearMarkdown(on: self.ticket.first?.detail ?? ""))
.padding()
.fixedSize(horizontal: false, vertical: true)
Text("Room Number")
.fontWeight(.bold)
.padding()
Text(self.ticket.first?.ticketCustomFields.first(where: {$0.definitionId == 14})?.restValue ?? "NOT PROVIDED")
.padding()
Text("Computer Number")
.fontWeight(.bold)
.padding()
Text(self.ticket.first?.ticketCustomFields.first(where: {$0.definitionId == 11})?.restValue ?? "NOT PROVIDED")
.padding()
Text("Phone Number")
.fontWeight(.bold)
.padding()
Text(self.ticket.first?.ticketCustomFields.first(where: {$0.definitionId == 15})?.restValue ?? "NOT PROVIDED")
.padding()
}
Divider()
Text("Notes")
.fontWeight(.bold)
.padding()
List(ticketNotes) { ticketNote in
VStack(alignment: .leading, spacing: 10) {
Text(ticketNote.prettyUpdatedString)
.padding()
Text(ticketNote.mobileNoteText)
.padding()
.fixedSize(horizontal: false, vertical: true)
}
}
}
.onAppear {
FetchTicketNotes().getTicketNotes(id: self.id, userApi: self.userApi) { ticketNotes in
self.ticketNotes = ticketNotes
}
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
Divider()
Section(header: Text("Create New Note")
.fontWeight(.bold)
.padding()
.padding(10)
.frame(maxWidth: .infinity)) {
TextField("Enter your note", text: $note)
.textFieldStyle(RoundedBorderTextFieldStyle())
.frame(width: 350)
.padding(15)
Button(action: {
self.showingNoteAlert = true
}) {
Text("Submit Note")
.frame(width: 300)
.padding(15)
.foregroundColor(Color.white)
.background(Color.orange)
.cornerRadius(5)
}.buttonStyle(BorderlessButtonStyle()
).actionSheet(isPresented:self.$showingNoteAlert) {
ActionSheet(
title: Text("Are you sure you want to add this note to \(displayClient)'s ticket?"),
message: Text("\(self.note)"),
buttons: [
.default(Text("Submit"))
{
self.createTicketNote.CreateNoteAction(ticketId: self.id, userApi: self.userApi, techNote: self.note);
self.note = "";
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
},
.cancel(){
self.note = ""
}])
}
}
Divider()
Section(header: Text("Change Ticket Status")
.fontWeight(.bold)
.padding()
.padding(10)
.frame(maxWidth: .infinity)) {
Button(action: {
self.showingOpenAlert = true
}) {
Text("Open")
.frame(width: 300)
.padding(15)
.foregroundColor(Color.white)
.background(Color.green)
.cornerRadius(5)
}.buttonStyle(BorderlessButtonStyle()).alert(isPresented:self.$showingOpenAlert) {
Alert(
title: Text("Are you sure you want change \(displayClient)'s ticket to Open?"),
primaryButton: .default(Text("Open"))
{
self.ticketStatusAction.TicketAction(ticketId: self.id, userApi: self.userApi, desiredStatus: 1);
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
},
secondaryButton: .cancel())
}
Spacer()
Button(action: {
self.showingPendingAlert = true
}) {
Text("Pending")
.frame(width: 300)
.padding(15)
.foregroundColor(Color.white)
.background(Color.yellow)
.cornerRadius(5)
}.buttonStyle(BorderlessButtonStyle()).alert(isPresented:self.$showingPendingAlert) {
Alert(
title: Text("Are you sure you want to set \(displayClient)'s ticket to Pending?"),
primaryButton: .default(Text("Pending"))
{
self.ticketStatusAction.TicketAction(ticketId: self.id, userApi: self.userApi, desiredStatus: 2);
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
},
secondaryButton: .cancel())
}
Spacer()
Button(action: {
self.showingDepotAlert = true
}) {
Text("Depot")
.frame(width: 300)
.padding(15)
.foregroundColor(Color.white)
.background(Color.blue)
.cornerRadius(5)
}.buttonStyle(BorderlessButtonStyle()).alert(isPresented:self.$showingDepotAlert) {
Alert(
title: Text("Are you sure you want to depot \(displayClient)'s ticket?"),
primaryButton: .default(Text("Depot"))
{
self.ticketStatusAction.TicketAction(ticketId: self.id, userApi: self.userApi, desiredStatus: 6);
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
},
secondaryButton: .cancel())
}
Spacer()
Button(action: {
self.showingCloseAlert = true
}) {
Text("Close")
.frame(width: 300)
.padding(15)
.foregroundColor(Color.white)
.background(Color.red)
.cornerRadius(5)
}.buttonStyle(BorderlessButtonStyle()).alert(isPresented:self.$showingCloseAlert) {
Alert(
title: Text("Are you sure you want to close \(displayClient)'s ticket?"),
primaryButton: .destructive(Text("Close"))
{
self.ticketStatusAction.TicketAction(ticketId: self.id, userApi: self.userApi, desiredStatus: 3);
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
}
}
},
secondaryButton: .cancel())
}
Spacer()
}
}.padding()
.padding(.bottom, keyboard.currentHeight)
.edgesIgnoringSafeArea(.bottom)
.animation(.easeOut(duration: 0.16))
}
}
答案 0 :(得分:0)
这里有很多错误。首先,将getTicketNotes
方法参数的解码和完成块更新为[TicketNotes]
。
class FetchTicketNotes: ObservableObject {
func getTicketNotes(id: Int, userApi: String, completion: @escaping ([Note]) -> ()) {
guard let url = URL(string: "LINK HERE") else { return }
URLSession.shared.dataTask(with: url) {(data, _, _) in
let ticketNotes = try! JSONDecoder().decode([Note].self, from: data!)
DispatchQueue.main.async {
completion(ticketNotes)
}
}
.resume()
}
}
然后修改.onAppear
,
.onAppear {
//...
FetchTicketNotes().getTicketNotes(id: self.id, userApi: self.userApi) { ticketNotes in
self.ticketNotes = ticketNotes
}
}
最后,
@State var ticketNotes: [Note] = []
//...
Text(clearMarkdown(on: note.prettyUpdatedString))
答案 1 :(得分:0)
这可能不是最佳解决方案,但它适合我的情况。我确实找到了[TicketDetails] JSON所要查找的数据,因此这使它变得不那么复杂了。在.onAppear函数中,我捕获了相关数据。
声明了变量
@State var ticketNotes: [Notes] = []
在出现时更改
.onAppear {
FetchTick().getTicket(id: self.id, userApi: self.userApi) { (ticketDetails) in
self.ticket = [ticketDetails]
self.ticketNotes = ticketDetails.notes
}
}
我使用ForEach遍历数组中的每个项目
VStack(alignment: .leading, spacing: 10) {
ForEach(ticketNotes, id: \.self) {ticketNote in
Text(clearMarkdown(on: "\(ticketNote.prettyUpdatedString) '\(ticketNote.mobileNoteText)'"))
.padding()
}
}