Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Json 需要解码字典<;字符串,任意>;但是找到了一个数组,而不是嵌套容器_Json_Swift_Parsing_Core Data_Codable - Fatal编程技术网

Json 需要解码字典<;字符串,任意>;但是找到了一个数组,而不是嵌套容器

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

因此,我尝试使用可编码协议解析此JSON:

基本上是100个随机用户

这是decoder中的用户类初始值设定项,我需要它,因为用户是核心数据模型中的一个实体:

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
调用的,这很好,非常好!现在,我不知道我说的是否愚蠢,但我希望初始值设定项能够处理核心数据数据库中新用户的保存。我用工具打开了数据库,但它没有好像没有。你有什么提示吗?再次非常感谢!