Json 需要解码字典<;字符串,任意>;但是找到了一个数组,而不是嵌套容器
因此,我尝试使用可编码协议解析此JSON: 基本上是100个随机用户 这是decoder中的用户类初始值设定项,我需要它,因为用户是核心数据模型中的一个实体:Json 需要解码字典<;字符串,任意>;但是找到了一个数组,而不是嵌套容器,json,swift,parsing,core-data,codable,Json,Swift,Parsing,Core Data,Codable,因此,我尝试使用可编码协议解析此JSON: 基本上是100个随机用户 这是decoder中的用户类初始值设定项,我需要它,因为用户是核心数据模型中的一个实体: required convenience public init(from decoder: Decoder) throws { let managedObjectContext = CoreDataStack.sharedInstance.persistentContainer.viewContext
required convenience public init(from decoder: Decoder) throws {
let managedObjectContext = CoreDataStack.sharedInstance.persistentContainer.viewContext
guard let entity = NSEntityDescription.entity(forEntityName: "User", in: managedObjectContext) else {
fatalError("Failed to decode User")
}
self.init(entity: entity, insertInto: managedObjectContext)
let container = try decoder.container(keyedBy: CodingKeys.self)
let results = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .results)
let name = try results.nestedContainer(keyedBy: CodingKeys.self, forKey: .name)
firstName = try name.decode(String.self, forKey: .firstName)
lastName = try name.decode(String.self, forKey: .lastName)
let location = try results.nestedContainer(keyedBy: CodingKeys.self, forKey: .location)
let street = try location.decode(String.self, forKey: .street)
let city = try location.decode(String.self, forKey: .city)
let postcode = try location.decode(String.self, forKey: .postcode)
address = street + ", " + city + ", " + postcode
email = try results.decode(String.self, forKey: .email)
let pictures = try results.nestedContainer(keyedBy: CodingKeys.self, forKey: .pictures)
pictureURL = try pictures.decode(String.self, forKey: .pictureURL)
}
这是有缺陷的生产线:
let results = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .results)
下面是完整的错误:
typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil))
类型不匹配(Swift.Dictionary,Swift.DecodingError.Context(codingPath:[],debugDescription:“应解码字典,但找到了一个数组。”,underlineerror:nil))
我认为这是由于JSON的结构,即在键“results”下包含100个元素的数组,我认为问题可能在于将它们全部放在一起。
我应该如何处理这个问题?这是一个非常简化的版本,但它可以正确处理Json数据
struct Result : Codable {
let results: [User]
}
struct User: Codable {
let gender: String
let name: Name
}
struct Name: Codable {
let title: String
let first: String
let last: String
}
let decoder = JSONDecoder()
let data = jsonString.data(using: .utf8) //Replace with url download
do {
let json = try decoder.decode(Result.self, from: data!)
} catch {
print(error)
}
错误很明显:
results
的值是一个数组,nestedContainers
需要一个字典
要解码用户数组,您需要核心数据类之外的伞形结构
struct Root : Decodable {
let results: [User]
}
对Root
进行解码时,为每个数组项调用User
中的init
方法
要使用nestedContainers
,必须分离编码键
这是没有核心数据的init
方法postcode
可以是String
或Int
private enum CodingKeys: String, CodingKey { case name, location, email, picture }
private enum NameCodingKeys: String, CodingKey { case first, last }
private enum LocationCodingKeys: String, CodingKey { case street, city, postcode }
private enum PictureCodingKeys: String, CodingKey { case large, medium, thumbnail }
required convenience public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let nameContainer = try container.nestedContainer(keyedBy: NameCodingKeys.self, forKey: .name)
let firstName = try nameContainer.decode(String.self, forKey: .first)
let lastName = try nameContainer.decode(String.self, forKey: .last)
let locationContainer = try container.nestedContainer(keyedBy: LocationCodingKeys.self, forKey: .location)
let street = try locationContainer.decode(String.self, forKey: .street)
let city = try locationContainer.decode(String.self, forKey: .city)
let postcode : String
do {
let postcodeInt = try locationContainer.decode(Int.self, forKey: .postcode)
postcode = String(postcodeInt)
} catch DecodingError.typeMismatch {
postcode = try locationContainer.decode(String.self, forKey: .postcode)
}
let address = street + ", " + city + ", " + postcode
let email = try container.decode(String.self, forKey: .email)
let pictureContainer = try container.nestedContainer(keyedBy: PictureCodingKeys.self, forKey: .picture)
let pictureURL = try pictureContainer.decode(URL.self, forKey: .large)
}
什么是
CodingKeys
?在User init方法中不能处理整个result
数组,它只需要处理一个用户。如果没有,则需要一个结果结构或类来处理数组。为什么这么多容器都由相同的键进行键控?这无疑是解析此JSON的一个很好的解决方案,但在核心数据NSManagedObject
子类中却非常不合适environment@vadian没错,我故意将答案集中在Json问题上,忽略了核心数据位,认为保存到核心数据可以单独处理。这里的问题不是所有的值都仍然在Json中最外部的键“results”下的数组中?目前init(from
被称为结果的一项
数组作为参数传递所以,很抱歉这个愚蠢的问题,但是我应该如何调用它?现在它的名称是这样的:let decoder=JSONDecoder()let json=try decoder.decode(User.self,from:data)
在DataTask结束时,我缺少了什么?没有,正如回答中提到的,您必须添加伞形结构并解码decoder.decode(Root.self,
User中的init
方法是从results
调用的,这很好,非常好!现在,我不知道我说的是否愚蠢,但我希望初始值设定项能够处理核心数据数据库中新用户的保存。我用工具打开了数据库,但它没有好像没有。你有什么提示吗?再次非常感谢!