Swift 5:如何从 JSONDecoder().decode 获取数据?

Posted

技术标签:

【中文标题】Swift 5:如何从 JSONDecoder().decode 获取数据?【英文标题】:Swift 5: How can i get data from JSONDecoder().decode? 【发布时间】:2020-11-26 11:05:08 【问题描述】:

我从 Google 翻译 API 获得 JSON:


    data =     
        translations =         (
                        
                detectedSourceLanguage = en;
                translatedText = "\U0434\U0430\U043d\U043d\U044b\U0435";
            
        );
    ;

然后我这样做:

     if data != nil && error == nil 
        
        let decoder = JSONDecoder()
        
        do 
        
            let translated = try! decoder.decode(Data.self, from: data!)
            dump(translated)
         catch 
            print(error)
        
    

我拿了这个:

MyVocabulary.JSONTranslator.Data
  ▿ data: MyVocabulary.JSONTranslator.Data.Translations
    ▿ translations: 1 element
      ▿ MyVocabulary.JSONTranslator.Data.Translations.TranslatedText
        - detectedSourceLanguage: "en"
        - translatedText: "Работа"

我的结构:

 struct Data: Codable 
        
        struct Translations: Codable 
            
            struct  TranslatedText: Codable 
                var detectedSourceLanguage: String
                var translatedText: String
                
                enum CodingKeys: String, CodingKey
                    case detectedSourceLanguage
                    case translatedText
                
                
                init(from decoder: Decoder) throws 
                    let container = try decoder.container(keyedBy: CodingKeys.self)
                    self.translatedText = try container.decode(String.self, forKey: .translatedText)
                    self.detectedSourceLanguage = try container.decode(String.self, forKey: .detectedSourceLanguage)
                  
            
            var translations: ([TranslatedText])
        
        let data: Translations
    

如何在解码后从 TranslatedText 获取属性到“do”块中的 var?

【问题讨论】:

【参考方案1】:

主要错误是命名自定义结构 Data,因为它会干扰 Foundation 结构 Data 并且解码 Data.self 失败。

您不需要自定义初始化程序或 CodingKeys,这 3 个结构就足够了

struct Root: Decodable   let data: Translations 
struct Translations: Decodable  let translations: [TranslatedText] 
struct TranslatedText: Decodable  let detectedSourceLanguage, translatedText : String 

现在解码Root.self 并得到translatedText,如下所述

let decoder = JSONDecoder()
do 
    let translated = try decoder.decode(Root.self, from: data!)
    let translatedText = translated.data.translations.first?.translatedText
    print(translatedText)
 catch 
    print(error)

【讨论】:

【参考方案2】:

您提供的 JSON 无效。我假设您的意思是 JSON 是这样的:


    "data": 
        "translations": [
                
                    "detectedSourceLanguage": "en",
                    "translatedText": "\U0434\U0430\U043d\U043d\U044b\U0435"
                
        ]
    

除非您想要自定义 JSON 解码,否则您不必输入 CodingKeys 枚举或 init(from:)。您可以通过让默认解码自动发生来简化它。

将您的模型修改为:

struct Response: Codable 
    var data: Data


struct Data: Codable 
    var translations: [Translation]


struct Translation: Codable 
    var detectedSourceLanguage: String
    var translatedText: String

在您的do 块内,您不应强制解开try。您应该将try! 更改为try,这样当尝试失败时,它将触发catch 块。否则如果你使用try!会导致应用崩溃

do里面你可以说:

do 
    let response = try decoder.decode(Response.self, from: data!)
    let data = response.data
    let translations = data.translations
    let firstTranslation = translations[0]
    let detectedSourceLanguage = firstTranslation.detectedSourceLanguage
    let translatedText = firstTranslation.translatedText

【讨论】:

JSON 不等同于问题中的字典转储。键翻译的值是一个数组。 JSON 正是我发布的,如果是你写的会更容易 @VovaKotsiubenko 我编辑了我的答案以使翻译成为一个数组。 JSONDecoder 足够强大,可以将对象数组从 JSON 解码为 Array

以上是关于Swift 5:如何从 JSONDecoder().decode 获取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何准备 API 响应以在 swift 中与 jsonDecoder 一起使用

如何在 swift 中使用 JSONDecoder 输入调整?

Swift - 使用 JSONDecoder 解码 JSON 数据

Swift4 JSONDecoder 期望解码 Dictionary<String, Any> 但找到了一个数组 [重复]

Swift - 将类型动态传递给 JSONDecoder

如何在 swift 4.1 和 xcode 9.3 中使用 JSONDecoder 解码嵌套的 JSON 数组和对象?