快速嵌套嵌套循环

时间:2018-06-20 07:45:57

标签: ios swift nested-loops

我正在尝试快速解析嵌套的迭代循环 我正在从Web服务获取以下格式的响应

{
    "categories": [{
        "name": "Default Category",
        "id": "default_category",
        "children": [{
            "uuid": "783f491fef5041438fb7a2c3bf6a3650",
            "name": "Accessories",
            "children": [{
                "uuid": "d21b4491ff784a9bae88de279b99fac3",
                "name": "All Accessories",
                "children": [{
                        "uuid": "2b1a23c4107844ad8a7afc1b324d0ffd",
                        "name": "Belts",
                        "children": [{
                                "uuid": "2b1a23c4107844ad8a7afc1b324d0ffd",
                                "name": "Belts",
                                "children": []

                            },
                            {
                                "uuid": "2b1a23c4107844ad8a7afc1b324d0ffd",
                                "name": "Belts",
                                "children": []
                            }
                        ]
                    },
                    {
                        "uuid": "a1c2a64c36c2461cad3d5f850e4fd0f5",
                        "name": "Hats",
                        "children": []
                    },
                    {
                        "uuid": "8f26bc764b8342feaa0cb7f3b96adcae",
                        "name": "Scarves",
                        "children": []
                    },
                    {
                        "uuid": "aa1116d1a0254ecea836cc6b32eeb9e0",
                        "name": "Sunglasses",
                        "children": []
                    },
                    {
                        "uuid": "9d7033233e8f47eaa69eb1aaf2e98cdd",
                        "name": "Watches",
                        "children": []
                    }
                ]
            }]
        }],
        "uuid": "6a23415771064e7aaad59f84f8113561"
    }]
}

在类别中,有一个“儿童”键,而该键又可以包含另一个儿童,依此类推。 我想不断地在子项键内部循环,直到子项键为空,然后将最后一个子项插入数据库中。

以下是我完成的代码

     for currentCategory in mainCategories {


    // guard against if there are child categories
            guard var children = currentCategory.children, children.count > 0 else {
                //  Save the context
                self.coreData.saveStore()
                continue
            }                    
            for thisChildCategory in children {

                if thisChildCategory.children?.count > 0 {
                    for innerChildCategory in thisChildCategory.children! {
                        print("innerChildCategory name \(String(describing: innerChildCategory.name))")
                    }
                }

                if let child = thisChildCategory.children {
                    children = child
                }

                //  Create new object
                if let currentChildCategory  = self.coreData.insertNewObject(CoreDataEntities.BijouCategories.rawValue,
                    keyValues: ["id" : thisChildCategory.id! as Optional<AnyObject>,
                        "uuid" : thisChildCategory.uuid as Optional<AnyObject>,
                        "name" : thisChildCategory.name! as Optional<AnyObject>,
                        "gender" : thisChildCategory.gender as Optional<AnyObject>!,
                        "active" : NSNumber(value: false)]) as? BijouCategories {

                    //  Set as parent category
                    currentChildCategory.parentCategory = parentCategory


                    //  Save the context
                    self.coreData.saveStore()

                }
            }

        }

但这不会将所有最后一个子类别保存在数据库中。

4 个答案:

答案 0 :(得分:2)

快捷键4

您应该让Swift 4的codable为您完成工作。

您可以使用以下类作为结构,但是我发现如果您打算编辑数据,使用类会更好。

class Categories: Codable {
     var categories: [CategoryItems]
}

class CategoryItems: Codable {
    var name: String?
    var id: String?
    var uuid: String?
    var children: [CategoryItems]?

required init(from decoder: Decoder) throws {
    var container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decodeIfPresent(String.self, forKey: CodingKeys.name)
    id = try container.decodeIfPresent(String.self, forKey: CodingKeys.id)
    uuid = try container.decodeIfPresent(String.self, forKey: CodingKeys.uuid)
    children = try container.decodeIfPresent([CategoryItems].self, forKey: CodingKeys.children)
    if children != nil, children!.count == 0 {
        children = nil
    }
}

您可以在此处看到我们添加了创建具有一个CategoryItems数组的根级别类“ Categories”。 CategoryItems中具有所有可能的值,但是数组中的每个项目可能具有也可能没有所有可能的值,因此它们是可选的。重要的是孩子,这是可选的。然后在要求的初始化中,如果键值对在解码时可用,我们只会选择可选值。如果项数为零,我还将子级设置为nil,这是可选的,但在以后执行if语句时会有所帮助。

然后使用这些可编码类对json进行解码,请使用以下代码。

func decode(jsonData data: Data) {
    let decoder = JSONDecoder()
    do {
        let decoded = try decoder.decode(Categories.self, from: data)
    }
    catch let error as NSError {
        print("JSON Decode error = ", error)
    }
}

如果您想进行快速测试以查看您是否获得了我所深化的子级,则只需在解码后的变量上运行以下命令即可。

for i in decoded.categories.first!.children!.first!.children!.first!.children!.first!.children! {
     print(i.name)
     print(i.uuid)
}

答案 1 :(得分:1)

创建了一个模型类,以树的形式容纳您的嵌套子代。

class Children {
    var uuid: String?
    var name: String?
    var children: [Children] = [Children(array: [])]
    init(array: NSArray) {
        let childrenDic = array[0] as! NSDictionary
        uuid = childrenDic["uuid"] as? String
        name = childrenDic["name"] as? String
        children[0] = Children.init(array: childrenDic["children"] as! NSArray)
    }
}

使用方式

var childrenModel = Children.init(array: yourArray)

答案 2 :(得分:0)

建议使用2个以上嵌套级别的递归函数。 递归表示该函数调用自身。

这是一个简单的示例,假设jsonString是问题中给定的JSON。

函数parseCategory传递children数组和UUID字符串作为parent标识符。 print行是将对象保存在Core Data中的位置,当然您可以将创建的Core Data对象作为parent传递,也可以设置关系。

func parseCategory(children: [[String:Any]], parent: String) {
    for child in children {
        print("Save in Core Data", child["name"] as! String, parent)
        let descendants = child["children"] as! [[String:Any]]
        parseCategory(children:descendants, parent: child["uuid"] as! String)
    }
}

let data = Data(jsonString.utf8)
do {
    let json = try JSONSerialization.jsonObject(with: data) as! [String:Any]
    parseCategory(children: json["categories"] as! [[String:Any]], parent: "")
} catch { print(error)}

输出为

"Save in Core Data Default Category 
Save in Core Data Accessories 6a23415771064e7aaad59f84f8113561
Save in Core Data All Accessories 783f491fef5041438fb7a2c3bf6a3650
Save in Core Data Belts d21b4491ff784a9bae88de279b99fac3
Save in Core Data Belts 2b1a23c4107844ad8a7afc1b324d0ffd
Save in Core Data Belts 2b1a23c4107844ad8a7afc1b324d0ffd
Save in Core Data Hats d21b4491ff784a9bae88de279b99fac3
Save in Core Data Scarves d21b4491ff784a9bae88de279b99fac3
Save in Core Data Sunglasses d21b4491ff784a9bae88de279b99fac3
Save in Core Data Watches d21b4491ff784a9bae88de279b99fac3"

答案 3 :(得分:-1)

我建议您使用ObjectMapper而不是手动解开json。 https://github.com/Hearst-DD/ObjectMapper

那么一切都应该更干净

class Child: Mappable {

    var uuid: String?
    var name: String?
    var childern: [Child]?

    required init?(map: Map) {

    }

    // Mappable
    func mapping(map: Map) {
        uuid <- map["uuid"]
        name <- map["name"]
        childern <- map["childern"]
    }

}

class Category: Mappable {

    var _id: String? //id is the reserved word 
    var name: String?
    var childern: [Child]?

    required init?(map: Map) {

    }

    // Mappable
    func mapping(map: Map) {
        _id <- map["id"]
        name <- map["name"]
        childern <- map["childern"]
    }

}