【问题标题】:SwiftUI ObservableObject create non array @PublishedSwiftUI ObservableObject 创建非数组@Published
【发布时间】:2021-01-25 03:59:42
【问题描述】:

我尝试使用非数组 @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",
    }
}

【问题讨论】:

  • 你不需要实现.init(from:)或自定义CodingKey——只要符合Decodable/Encodable(或Codable)就足够了,即struct ShopDetail: Codable { var gallery: [Gallery]?; var info: Info? }。 ..除此之外,您尝试在nil 值上使用!,您会收到此错误。为什么这个值是 nil 很难说,因为我们不知道你正在解码的 JSON 是什么样的
  • @NewDev 使用示例 json 编辑
  • 数据不会是nil,至少会是一个空字符串""
  • 如果示例 JSON 是正确的,那么您不需要将 ShopDetail.Info 设为可选,而 ShopDetail.gallery 可以只是 [Gallery] - 不是可选数组。另外,避免使用! 强制展开。很难确定错误是什么,因为您没有显示错误实际发生的位置。我的猜测是你试图在加载之前访问ShopDetailJSON.info,但它失败了。如果是这样,请输入条件:if let info = details.info { Text(info.name) }

标签: swift swiftui observableobject


【解决方案1】:

这是对代码中发生的情况的猜测,但如果 JSON 数据从不为空,正如您在 cmets 中所说,您可能正在尝试访问 not -尚未更新 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()
       }
   }
}

【讨论】:

    猜你喜欢
    • 2021-10-14
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 2021-12-14
    • 2021-11-01
    • 2020-07-31
    相关资源
    最近更新 更多