【问题标题】:Nested repeatative loop in swift快速嵌套重复循环
【发布时间】:2018-06-20 07:45:57
【问题描述】:

我正在尝试快速解析嵌套的迭代循环 我收到以下格式的网络服务响应

{
    "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"
    }]
}

在类别里面,有一个'children'键,它又可以包含另一个孩子等等。 我想在子键中不断循环,直到子键为空并将最后一个子键插入数据库。

下面是我做的代码

     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()

                }
            }

        }

但这并没有保存数据库中的所有最后一个子类别。

【问题讨论】:

  • 顺便说一句,as Optional&lt;AnyObject&gt; 非常规,请改用as? AnyObject
  • 这种方式不靠谱,需要重新考虑数据结构设计
  • 你能发布一张显示你的核心数据模型图的图片吗?
  • 使用这个网站来创建模型数据,我已经试过把你的模型数据放到它的工作上。 json4swift.com
  • 正如其中一个答案所建议的,您应该使用递归函数

标签: ios swift nested-loops


【解决方案1】:

如果嵌套级别超过 2 个,建议使用递归函数。 递归表示函数调用自己。

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

函数parseCategorychildren 数组和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"

【讨论】:

    【解决方案2】:

    斯威夫特 4

    您应该让 Swift 4 的可编码部分为您完成这项工作。

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

    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 包含所有可能的值,但数组中的每个项目可能具有也可能不具有所有可能的值,因此它们是可选的。重要的是孩子是可选的。然后在 required init 中,我们仅在解码时键值对可用时才设置可选值。如果项目为零,我还将子项设置为 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)
    }
    

    【讨论】:

      【解决方案3】:

      创建了一个模型类,以树的形式保存嵌套的子级。

      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)
      

      【讨论】:

        【解决方案4】:

        我建议您使用 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"]
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-18
          • 2017-09-30
          • 2010-10-13
          • 1970-01-01
          相关资源
          最近更新 更多