swiftUI 中来自不同数据模型(API 响应)的详细视图
Detail View from different Data Model (API response) in swiftUI
用代码深入阐述问题
我有一个数据模型(API 响应),我正在使用它来创建列表。列表项还应在详细视图中显示其详细信息。问题是列表项的详细信息来自不同的 API,而不是用于创建列表的 API。一项的 ID 被传递给 API,后者作为响应提供该项目的详细信息。
这是数据模型(仅包含特定问题的项目):
struct TrackSample : Codable, Identifiable {
let id = UUID()
let success : Bool
let message : String
let trackResponse : [TrackResponse]
enum CodingKeys: String, CodingKey{
case success = "IsSuccess"
case message = "Message"
case trackResponse = "ResponseData"
}}
struct TrackResponse : Codable, Identifiable {
let id = UUID()
let patientID : String
let name : String
let testCount : Int
//..some more//
enum CodingKeys: String, CodingKey {
case patientID = "PatientId"
case name = "Name"
case status = "Status"
case testCount = "NoOfTests"
}}
ViewModel 获取 API 响应(TrackResource() 是一个不同的 class,它实现了网络调用):
class TrackViewModel : ObservableObject
{
@Published var trackReport = [TrackResponse]()
@Published var navigate:Bool = false
//other var
private let trackResource = TrackResource()
func getTrack()
{
//code to get data based on which button is clicked in Options
screen.
There are five options to choose:
if else statement follows//
centerID = "100"
let trackRequest = TrackRequest(CenterId:centerID,
SearchText:searchText, StartDate:startDate, EndDate:endDate)
trackResource.track(trackRequest: trackRequest)
{
response in
if(response?.success==true)
{
DispatchQueue.main.async {
self.navigate = true
self.trackReport = response?.trackResponse ?? []
}
}
else
{
DispatchQueue.main.async {
self.errorMessage = response?.message ?? "No Data"
// self.isPresentingAlert
}
}}}}
表示列表的视图 YdaySample :
struct YdaySample: View {
@ObservedObject var tracking : TrackViewModel
var body: some View {
NavigationView{
List{
ForEach(tracking.trackReport)
{ truck in
NavigationLink(destination: TrackDetail(track:truck))
{
YdayRow(truck: truck)
}
}
if(tracking.trackReport.isEmpty){
Text("No Record Found !")
//formatting
}}}}}
struct YdaySample_Previews: PreviewProvider {
static var previews: some View {
YdaySample(tracking: TrackViewModel())
}}
YdayRow() :
struct YdayRow: View {
var truck : TrackResponse
var body: some View {
VStack{
HStack{
Text(truck.name)
//formatting//
}
HStack{
Text("P.Id:")
//formatting//
Text(truck.patientID)
//formatting//
Spacer()
Text("Total Test:")
//formatting//
Text("\(truck.testCount)")
//formatting//
}}}}
struct YdayRow_Previews: PreviewProvider {
static var previews: some View {
YdayRow(truck: TrackResponse(patientID: "1", name: "test",
status: "null", crmNo: "null",
recordDate: "somedate", uniqueID: "null", testCount: 4))
}
}
TrackDetail() 已更新:
struct TrackDetail: View {
var track: TrackResponse
@State var patientDetail: DetailResponse
var body: some View {
VStack{
HStack{
Text(track.name)
//formatting
}.frame(maxWidth: .infinity, alignment: .center)
HStack{
Text("P.Id:")
//formatting
Text(track.patientId)
//formatting
}
List{ForEach(patientDetail.detailResponse)
{detail in
HStack
{ Text("Barcode: ")
Text(detail.barcode)
}
}
}.onAppear{
Task{
do{
try await getDetail()
}catch{
Alert(title: Text("Error"),message: Text("Not Found"),
dismissButton: .cancel())
}}}}}
func getDetail() async throws{
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "xx.xxx.xx.xx"
urlComponents.path = "/api/reports/getalltests"
urlComponents.queryItems = [URLQueryItem(name: "centerId", value:
("\(668)")),URLQueryItem(name: "patientId", value: "\
(track.patientId)")]
let url = urlComponents.url
var request = URLRequest(url: url!)
print(request)
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-
Type")
request.setValue("Basic xcvgjhalddjdj",forHTTPHeaderField:
"Authorization")
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data,
response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
if let data = data
{
let dataString = String(data:data,encoding: .utf8)
print(dataString!)
do{
let json = try JSONDecoder().decode(DetailResponse.self,
from: data)
print(json)
DispatchQueue.main.async {
self.patientDetail = json
}
}catch{
print("error \(error)")
}
}
};task.resume()
}}
struct TrackDetail_Previews: PreviewProvider {
static var previews: some View {
TrackDetail(track: TrackResponse(patientId: "4193716", name: "Dummy
Report HCV RNA", status: "null", crmNo: "null", recordDate: "2022-
04-15", uniqueId: "null", testCount: 10), patientDetail:
DetailResponse(success: false, message: "mess", detailResponse:
[]))
}}
print(request) 正在根据需要正确打印 URL url 中的 patientID 也是正确的 (http://xxx..x.x/api/reports/getalltests/centerId=668&patientId=(tapped id))
但它在解码时抛出错误 说“此请求已被拒绝授权”错误 keynotfound(codingkeys(stringvalue: "ResponseData", intvalue:nil), Swift.decodingerror.context(codingpath: [],debugdescription: "No value associated with key CodingKeys(stringvalue: "ResponseData", intvalue:nil)("ResponseData", underlyingError:nil)
struct DetailResponse : Codable{
let success : Bool ?
let message : String
let detailResponse : [PatResponse]
enum CodingKeys: String, CodingKey{
case success = "IsSuccess"
case message = "Message"
case patResponse = "ResponseData"
}}
struct PatResponse : Codable, Identifiable {
var barcode: String
var:id String {barcode}
let testname : String?
let packageName : String?
let status: String?
let sampleRecievedTime: String?
let recordDate: String
enum CodingKeys: String, CodingKey {
case packageName = "PackageName"
case testname = "TestName"
case status = "Status"
case sampleRecievedTime = "SampleRecievedTime"
case recordDate = "RecordDate"
case barcode = "Barcode"
}}
///////**************//////////////////
详细视图显示名称和 ID,因为它们来自 TrackResponse
但是状态和条形码不是来自不同的API。
当用户 click/tap 列表中的项目时,patientID 和 centerId 作为 GET 请求中的查询参数发送,作为响应将提供与给定 patientId 关联的详细信息(中心 ID 是常量)。如何实现?
这样的怎么样?
struct TrackDetail: View{
var track: TrackResponse
@State var details: TrackDetails?
var body: some View{
HStack{
//Detail implementation
}.onAppear{
Task{
do{
try await doStuff()
}catch{
//Alert
}
}
}
}
func doStuff() async throws{
// pull Details from Api
}
}
用代码深入阐述问题
我有一个数据模型(API 响应),我正在使用它来创建列表。列表项还应在详细视图中显示其详细信息。问题是列表项的详细信息来自不同的 API,而不是用于创建列表的 API。一项的 ID 被传递给 API,后者作为响应提供该项目的详细信息。
这是数据模型(仅包含特定问题的项目):
struct TrackSample : Codable, Identifiable {
let id = UUID()
let success : Bool
let message : String
let trackResponse : [TrackResponse]
enum CodingKeys: String, CodingKey{
case success = "IsSuccess"
case message = "Message"
case trackResponse = "ResponseData"
}}
struct TrackResponse : Codable, Identifiable {
let id = UUID()
let patientID : String
let name : String
let testCount : Int
//..some more//
enum CodingKeys: String, CodingKey {
case patientID = "PatientId"
case name = "Name"
case status = "Status"
case testCount = "NoOfTests"
}}
ViewModel 获取 API 响应(TrackResource() 是一个不同的 class,它实现了网络调用):
class TrackViewModel : ObservableObject
{
@Published var trackReport = [TrackResponse]()
@Published var navigate:Bool = false
//other var
private let trackResource = TrackResource()
func getTrack()
{
//code to get data based on which button is clicked in Options
screen.
There are five options to choose:
if else statement follows//
centerID = "100"
let trackRequest = TrackRequest(CenterId:centerID,
SearchText:searchText, StartDate:startDate, EndDate:endDate)
trackResource.track(trackRequest: trackRequest)
{
response in
if(response?.success==true)
{
DispatchQueue.main.async {
self.navigate = true
self.trackReport = response?.trackResponse ?? []
}
}
else
{
DispatchQueue.main.async {
self.errorMessage = response?.message ?? "No Data"
// self.isPresentingAlert
}
}}}}
表示列表的视图 YdaySample :
struct YdaySample: View {
@ObservedObject var tracking : TrackViewModel
var body: some View {
NavigationView{
List{
ForEach(tracking.trackReport)
{ truck in
NavigationLink(destination: TrackDetail(track:truck))
{
YdayRow(truck: truck)
}
}
if(tracking.trackReport.isEmpty){
Text("No Record Found !")
//formatting
}}}}}
struct YdaySample_Previews: PreviewProvider {
static var previews: some View {
YdaySample(tracking: TrackViewModel())
}}
YdayRow() :
struct YdayRow: View {
var truck : TrackResponse
var body: some View {
VStack{
HStack{
Text(truck.name)
//formatting//
}
HStack{
Text("P.Id:")
//formatting//
Text(truck.patientID)
//formatting//
Spacer()
Text("Total Test:")
//formatting//
Text("\(truck.testCount)")
//formatting//
}}}}
struct YdayRow_Previews: PreviewProvider {
static var previews: some View {
YdayRow(truck: TrackResponse(patientID: "1", name: "test",
status: "null", crmNo: "null",
recordDate: "somedate", uniqueID: "null", testCount: 4))
}
}
TrackDetail() 已更新:
struct TrackDetail: View {
var track: TrackResponse
@State var patientDetail: DetailResponse
var body: some View {
VStack{
HStack{
Text(track.name)
//formatting
}.frame(maxWidth: .infinity, alignment: .center)
HStack{
Text("P.Id:")
//formatting
Text(track.patientId)
//formatting
}
List{ForEach(patientDetail.detailResponse)
{detail in
HStack
{ Text("Barcode: ")
Text(detail.barcode)
}
}
}.onAppear{
Task{
do{
try await getDetail()
}catch{
Alert(title: Text("Error"),message: Text("Not Found"),
dismissButton: .cancel())
}}}}}
func getDetail() async throws{
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "xx.xxx.xx.xx"
urlComponents.path = "/api/reports/getalltests"
urlComponents.queryItems = [URLQueryItem(name: "centerId", value:
("\(668)")),URLQueryItem(name: "patientId", value: "\
(track.patientId)")]
let url = urlComponents.url
var request = URLRequest(url: url!)
print(request)
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("application/json", forHTTPHeaderField: "Content-
Type")
request.setValue("Basic xcvgjhalddjdj",forHTTPHeaderField:
"Authorization")
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data,
response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Read HTTP Response Status code
if let response = response as? HTTPURLResponse {
print("Response HTTP Status code: \(response.statusCode)")
}
if let data = data
{
let dataString = String(data:data,encoding: .utf8)
print(dataString!)
do{
let json = try JSONDecoder().decode(DetailResponse.self,
from: data)
print(json)
DispatchQueue.main.async {
self.patientDetail = json
}
}catch{
print("error \(error)")
}
}
};task.resume()
}}
struct TrackDetail_Previews: PreviewProvider {
static var previews: some View {
TrackDetail(track: TrackResponse(patientId: "4193716", name: "Dummy
Report HCV RNA", status: "null", crmNo: "null", recordDate: "2022-
04-15", uniqueId: "null", testCount: 10), patientDetail:
DetailResponse(success: false, message: "mess", detailResponse:
[]))
}}
print(request) 正在根据需要正确打印 URL url 中的 patientID 也是正确的 (http://xxx..x.x/api/reports/getalltests/centerId=668&patientId=(tapped id))
但它在解码时抛出错误 说“此请求已被拒绝授权”错误 keynotfound(codingkeys(stringvalue: "ResponseData", intvalue:nil), Swift.decodingerror.context(codingpath: [],debugdescription: "No value associated with key CodingKeys(stringvalue: "ResponseData", intvalue:nil)("ResponseData", underlyingError:nil)
struct DetailResponse : Codable{
let success : Bool ?
let message : String
let detailResponse : [PatResponse]
enum CodingKeys: String, CodingKey{
case success = "IsSuccess"
case message = "Message"
case patResponse = "ResponseData"
}}
struct PatResponse : Codable, Identifiable {
var barcode: String
var:id String {barcode}
let testname : String?
let packageName : String?
let status: String?
let sampleRecievedTime: String?
let recordDate: String
enum CodingKeys: String, CodingKey {
case packageName = "PackageName"
case testname = "TestName"
case status = "Status"
case sampleRecievedTime = "SampleRecievedTime"
case recordDate = "RecordDate"
case barcode = "Barcode"
}}
///////**************////////////////// 详细视图显示名称和 ID,因为它们来自 TrackResponse 但是状态和条形码不是来自不同的API。
当用户 click/tap 列表中的项目时,patientID 和 centerId 作为 GET 请求中的查询参数发送,作为响应将提供与给定 patientId 关联的详细信息(中心 ID 是常量)。如何实现?
这样的怎么样?
struct TrackDetail: View{
var track: TrackResponse
@State var details: TrackDetails?
var body: some View{
HStack{
//Detail implementation
}.onAppear{
Task{
do{
try await doStuff()
}catch{
//Alert
}
}
}
}
func doStuff() async throws{
// pull Details from Api
}
}