我试图用非数组@Published项目创建一个ObservableObject。但是,我仍然不知道该怎么做。我尝试使用?这样做。但是,当我以Text((details.info?.name)!)
之类的方式显示它并返回Thread 1: Swift runtime failure: force unwrapped a nil value
时,我不知道问题是什么以及如何解决。是我创建可观察对象类的方法正确吗?
class ShopDetailJSON: ObservableObject {
@Published var info : Info?
init(){load()}
func load() {
URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print("No data in response: \(error?.localizedDescription ?? "Unknown error").")
return
}
if let decodedShopDetails = try? JSONDecoder().decode(ShopDetail.self, from: data) {
DispatchQueue.main.async {
self.info = decodedShopDetails.info!
}
} else {
print("Invalid response from server")
}
}.resume()
}
}
struct Info : Codable, Identifiable {
let contact : String?
let name : String?
var id = UUID()
enum CodingKeys: String, CodingKey {
case contact = "contact"
case name = "name"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
contact = try values.decodeIfPresent(String.self, forKey: .contact)
name = try values.decodeIfPresent(String.self, forKey: .name)
}
}
struct ShopDetail : Codable {
let gallery : [Gallery]?
let info : Info?
enum CodingKeys: String, CodingKey {
case gallery = "gallery"
case info = "info"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
gallery = try values.decodeIfPresent([Gallery].self, forKey: .gallery)
info = try values.decodeIfPresent(Info.self, forKey: .info)
}
}
示例JSON数据
{
"gallery": [],
"info": {
"contact": "6012345678",
"name": "My Salon",
}
}
答案 0 :(得分:0)
这个答案是关于代码中发生的事情的一个猜测,但是,如果JSON数据从不为空(如您在注释中所述),则可能是您试图访问 -yet-updated ShopDetailJSON.info
可选属性。
首先,进行一些清理。您不需要init(from:)
的自定义实现-在您的情况下,只需遵守Codable
就足够了。而且,如果JSON值不是可选的,则无需将它们设置为可选类型:
struct Info: Codable, Identifiable {
let contact : String
let name : String
var id = UUID()
}
struct ShopDetail: Codable {
let gallery : [Gallery]
let info : Info
}
然后,当您获取JSON时,您将不需要处理可选内容和强制解包!
(无论如何应避免这种情况):
if let decodedShopDetails = try? JSONDecoder().decode(ShopDetail.self, from: data {
DispatchQueue.main.async {
self.info = decodedShopDetails.info // no force-unwrap needed
}
}
在视图中,您需要检查info
属性是否不是nil
,然后才能访问其元素。
struct ContentView: View {
@ObservedObject var details: ShopDetailJSON
var body: some View {
Group() {
// on iOS14
if let info = details.info {
Text(info.name)
}
// pre iOS14
// if details.info != nil {
// Text(details.info!.name)
// }
}
.onAppear {
self.details.load()
}
}
}