2017-06-07 101 views
5

我试图执行新的Codable协议,所以我在我的结构中添加了Codable,但我的卡在解码JSON上。Swift 4 Codable解码json

这是我收到:

结构 -

struct Question { 
    var title: String 
    var answer: Int 
    var question: Int 
} 

客户端 -

...

guard let data = data else { 
    return 
} 

do { 
    self.jsonResponse = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] 
    let questionItems = self.jsonResponse?["themes"] as! [[String: Any]] 

    questionItems.forEach { 
     let item = Question(title: $0["title"] as! String, 
          answer: $0["answer"] as! Int, 
          question: $0["question"] as! Int) 
     questionData.append(item) 
    } 

} catch { 
    print("error") 
} 

这里是我现在,除了我不能找出解码器部分:

结构 -

struct Question: Codable { 
    var title: String 
    var answer: Int 
    var question: Int 
} 

客户端 -

...

let decoder = JSONDecoder() 
if let questions = try? decoder.decode([Question].self, from: data) { 
    // Can't get past this part 
} else { 
    print("Not working") 
} 

它打印 “不工作”,因为我不能让过去的decoder.decode部分。有任何想法吗?将根据需要发布任何额外的代码,谢谢!

编辑:

API JSON的示例:

{ 
    "themes": [ 
    { 
     "answer": 1, 
     "question": 44438222, 
     "title": "How many letters are in the alphabet?" 
    }, 
    { 
     "answer": 0, 
     "question": 44438489, 
     "title": "This is a random question" 
    } 
    ] 
} 

如果我打印self.jsonResponse我得到这个:

Optional(["themes": <__NSArrayI 0x6180002478f0>(
{ 
    "answer" = 7; 
    "question" = 7674790; 
    title = "This is the title of the question"; 
}, 
{ 
    "answer_" = 2; 
    "question" = 23915741; 
    title = "This is the title of the question"; 
} 

我的新代码:

struct Theme: Codable { 
    var themes : [Question] 
} 

struct Question: Codable { 
    var title: String 
    var answer: Int 
    var question: Int 
} 

..

if let decoded = try? JSONDecoder().decode(Theme.self, from: data) { 
    print("decoded:", decoded) 
} else { 
    print("Not working") 
} 
+0

打印出错误,看看它说什么。 – Kevin

+1

在第一个例子中,它不会与解码为'jsonResponse'的数据一起工作,因为这是一个JSON对象,而不是数组。您需要从''themes''键中获取数组(定义另一个具有此属性的'Codable'类型)。 – Hamish

+0

@Hamish哟那是我在想什么,但还不完全确定,谢谢! – SRMR

回答

7

如果你的JSON有结构

{"themes" : [{"title": "Foo", "answer": 1, "question": 2}, 
      {"title": "Bar", "answer": 3, "question": 4}]} 

你需要为themes对象等效。加入这个结构

struct Theme : Codable { 
    var themes : [Question] 
} 

现在可以解码JSON:

if let decoded = try? JSONDecoder().decode(Theme.self, from: data) { 
    print("decoded:", decoded) 
} else { 
    print("Not working") 
} 

Question对象是隐式解码。

+0

谢谢!我认为这正是我期待的关于我认为它可能工作的总体思路的特殊性。 “如果让解码”应该在我的'do'声明或其外部? – SRMR

+0

如果你想使用'do-catch',你不需要'if',但'decode'行必须在'do'范围内。 – vadian

+0

完美。我将我的JSON添加到了我原来的问题中,这看起来像是你在想它吗?当我运行新代码时,我仍然“不工作”,即使我知道我很接近正确的答案,但我无法弄清楚问题所在。我很难调试'如果让解码'陈述来弄清楚。 – SRMR

1

你得到这个错误,因为你的JSON很可能构造为这样:

{ 
    "themes": [ 
    { "title": ..., "question": ..., "answer": ... }, 
    { "title": ..., "question": ..., "answer": ... }, 
    { ... } 
    ], 
    ... 
} 

但是,你写的代码需要一个[Question]在顶层。你需要的是一个不同的顶级类型,其themes属性是[Question]。当您解码该顶级类型时,您的[Question]将被解码为themes密钥。

+0

这很有道理,我会努力实施,谢谢! – SRMR