如何使用 swift swift iOS 中的 swift 高阶函数从本地 json 创建 ViewModel

How to create ViewModel from local json with swift higher order function in swift iOS

我有一个本地 json 并创建了可以解析和获取数据的数据模型,我想从数据模型创建一个视图模型以在视图控制器中使用可以任何建议如何使用 swift 高阶函数。

JSON:

{
    "segment": {
        "user1": {
            "banners": {
                "order": 1,
                "items": [1, 3, 4]
            },
            "products": {
                "order": 2,
                "items": [1, 2, 3, 4]
            }
        },
        "user2": {
            "banners": {
                "order": 2,
                "items": [4, 3]
            },
            "products": {
                "order": 1,
                "items": [2, 3, 4]
            }
        }
    },
    "productsList": [{
        "productId": 1,
        "title": "Title of the product",
        "description": "Desciprtion of the product"
    }, {
        "productId": 2,
        "title": "Title of the product",
        "description": "Desciprtion of the product"
    }, {
        "productId": 3,
        "title": "Title of the product",
        "description": "Desciprtion of the product"
    }, {
        "productId": 4,
        "title": "Title of the product",
        "description": "Desciprtion of the product"
    }]
}

数据模型::

struct dataModel : Codable {
    let segment : Segment?
    let productsList : [ProductsList]?
    enum CodingKeys: String, CodingKey {
        case segment = "segment"
        case productsList = "productsList"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        segment = try values.decodeIfPresent(Segment.self, forKey: .segment)
        productsList = try values.decodeIfPresent([ProductsList].self, forKey: .productsList)
    }
}

struct Banners : Codable {
    let order : Int?
    let items : [Int]?
    enum CodingKeys: String, CodingKey {
        case order = "order"
        case items = "items"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        order = try values.decodeIfPresent(Int.self, forKey: .order)
        items = try values.decodeIfPresent([Int].self, forKey: .items)
    }
}

struct Products : Codable {
    let order : Int?
    let items : [Int]?
    enum CodingKeys: String, CodingKey {
        case order = "order"
        case items = "items"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        order = try values.decodeIfPresent(Int.self, forKey: .order)
        items = try values.decodeIfPresent([Int].self, forKey: .items)
    }
}

struct ProductsList : Codable {
    let productId : Int?
    let title : String?
    let description : String?
    enum CodingKeys: String, CodingKey {
        case productId = "productId"
        case title = "title"
        case description = "description"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        productId = try values.decodeIfPresent(Int.self, forKey: .productId)
        title = try values.decodeIfPresent(String.self, forKey: .title)
        description = try values.decodeIfPresent(String.self, forKey: .description)
    }
}

struct Segment : Codable {
    let user1 : User1?
    let user2 : User1?
    enum CodingKeys: String, CodingKey {
        case user1 = "user1"
        case user2 = "user2"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        user1 = try values.decodeIfPresent(User1.self, forKey: .user1)
        user2 = try values.decodeIfPresent(User1.self, forKey: .user2)
    }
}

struct User1 : Codable {
    let banners : Banners?
    let products : Products?
    enum CodingKeys: String, CodingKey {
        case banners = "banners"
        case products = "products"
    }
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        banners = try values.decodeIfPresent(Banners.self, forKey: .banners)
        products = try values.decodeIfPresent(Products.self, forKey: .products)
    }
}

在视图模型中,每个具有以下条件的用户都需要一组部分。

  1. 部分必须根据 order 键放置在 json 例如,如果 order 是 1 那么它应该是用户数组中的第一个元素,从某种意义上说是 2应该是用户数组中的第二个元素。
  2. items 数组表示 productsList 数组中的 productId,如果 items 数组有 3 那么在 user 数组中它应该追加 productId:3.

有了以上两个条件,我如何为user1和user2创建两个数组。根据上面 json 例如它应该 return 如下。

user1 = [<banners items products>, <products items products>] //Based on order key sorting in array.

user2 = [< products items products>, < banners items products>] //Based on order key sorting in array.

如下所示创建的 ViewModel 可以从 viewDidLoad 调用 viewModel,它应该 return 每个用户的数据。任何人都可以建议在上述条件下执行此操作的正确方法我花了很多时间来做它没有按预期工作。

struct viewModel {
    func getUser1Data() -> []{ ///As per json should return banners items as first element and then products items
        
    }
    func getUser2Data() -> [] { ///As per json should return products items as first element and then banners items
        
    }
}

struct User {
    var title: String?
    var description: String?
}

获取和解析函数 json。

  func getModelFromJson(fileName: String) -> dataModel? {
        let decoder = JSONDecoder()
        let url = Bundle.main.url(forResource: fileName, withExtension: "json")
        let data = try? Data(contentsOf: url!)
        do {
            let result = try decoder.decode(dataModel.self, from: data!)
            return result
        } catch {
            print(error)
        }
        return nil
    }

我会这样做(代码中的注释)...我不知道你为什么提到高阶函数,我看不出有任何理由在这里使用它...

struct Response: Codable {
    let segment: Segment
    let productsList: [ProductsList]
}

struct ProductsList: Codable {
    let productId: Int
    let title: String
    let description: String
}

struct Segment: Codable {
    let user1: User
    let user2: User
}

struct User: Codable {
    let banners: BannersProducts
    let products: BannersProducts

    // return items that are sorted the way you want.
    var items: [Int] {
        [banners, products]
            .sorted(by: { [=10=].order < .order })
            .flatMap { [=10=].items }
    }
}

// one type for both Banners and Products
struct BannersProducts: Codable {
    let order: Int
    let items: [Int]
}

func getUsersFromJson(fileName: String) -> (user1: [ProductsList], user2: [ProductsList]) {
    let decoder = JSONDecoder()
    let url = Bundle.main.url(forResource: fileName, withExtension: "json")!
    let data = try! Data(contentsOf: url)
    let response = try! decoder.decode(Response.self, from: data)
    // put the products in a dictionary for easy lookup
    let products = Dictionary(grouping: response.productsList, by: { [=10=].productId })
    let user1 = response.segment.user1.items.map { products[[=10=]]!.first! } // user1 products
    let user2 = response.segment.user2.items.map { products[[=10=]]!.first! }// user2 products
    return (user1, user2)
}