首页 > 解决方案 > JSON 模型建议

问题描述

我必须创建一个好的模型来将从 JSON 接收到的数据传递给我的其他控制器。你们会怎么做呢?我需要在项目中的任何地方访问我的结构内的这些属性,以便能够填充 UI 组件等。

这是我的 API 响应文件:

import Foundation
import Alamofire

struct Description: Decodable {
    let data: [data]
}

struct data: Decodable {

    let id:Int?
    let descricao:String?
    let urlImagem:String?
}

func callApi(completion: @escaping (String, String) -> Void) {

    guard let _url = URL(string: "https://alodjinha.herokuapp.com/categoria")else{return}
    Alamofire.request(_url).responseJSON { (response) in

        guard let info = response.data else{return}

        do{
            let dataParsed = try JSONDecoder().decode(Description.self, from: info)

            for aData in dataParsed.data {


                completion(aData.descricao!, aData.urlImagem!)
            }

        }catch{
        print("Error serialization: \(error)")


}
}
}

这是我收到的 JSON 模型:

{
  "data": [
    {
      "id": 1,
      "descricao": "Games",
      "urlImagem": "http:\/\/39ahd9aq5l9101brf3b8dq58.wpengine.netdna-cdn.com\/wp-content\/uploads\/2013\/06\/3D-Gaming.png"
    },
    {
      "id": 2,
      "descricao": "Livros",
      "urlImagem": "http:\/\/4.bp.blogspot.com\/-6Bta1H9d22g\/UJAIJbqcHhI\/AAAAAAAAKi4\/hvgjWrlFc64\/s1600\/resenha-missiologia.png"
    },
    {
      "id": 3,
      "descricao": "Celulares",
      "urlImagem": "http:\/\/pt.seaicons.com\/wp-content\/uploads\/2015\/11\/Mobile-Smartphone-icon.png"
    },
    {
      "id": 4,
      "descricao": "Inform\u00e1tica",
      "urlImagem": "http:\/\/portal.ifrn.edu.br\/campus\/ceara-mirim\/noticias\/ifrn-oferece-curso-de-informatica-basica-para-pais-dos-estudantes\/image_preview"
    },
    {
      "id": 5,
      "descricao": "Eletrodom\u00e9stico",
      "urlImagem": "http:\/\/classificados.folharegiao.com.br\/files\/classificados_categoria\/photo\/8\/sm_4d5ed3beb0f31b61cb9a01e46ecd0cf9.png"
    },
    {
      "id": 6,
      "descricao": "TVs",
      "urlImagem": "http:\/\/i.utdstc.com\/icons\/256\/terrarium-tv-android.png"
    },
    {
      "id": 7,
      "descricao": "Filmes e S\u00e9ries",
      "urlImagem": "https:\/\/pbs.twimg.com\/profile_images\/801033586438733824\/91Y_N91t_reasonably_small.jpg"
    },
    {
      "id": 8,
      "descricao": "M\u00f3veis e Decora\u00e7\u00f5es",
      "urlImagem": "https:\/\/image.flaticon.com\/icons\/png\/128\/148\/148188.png"
    },
    {
      "id": 9,
      "descricao": "Moda, Beleza e Perfumaria",
      "urlImagem": "http:\/\/icon-icons.com\/icons2\/196\/PNG\/128\/fashion_23852.png"
    },
    {
      "id": 10,
      "descricao": "Papelaria",
      "urlImagem": "http:\/\/esen.pt\/in\/images\/stories\/skills_256.png"
    }
  ]
}

非常感谢!

标签: jsonmodel-view-controlleralamofireswift4xcode9

解决方案


1. 模型重构

首先,让我们为data.
这样做是ImageData因为类型名称应该是 Pascal Cased(这只是一个很好的编码约定)。例如ClassName, StructName, PascalCase.
我们也不希望它被调用Data,因为这会重载Foundation's 的Data类型。

所以我们的模型将是:

struct Description: Decodable {
    let data: [ImageData]
}

struct ImageData: Decodable {
    let id: Int
    let descricao: String
    let urlImagem: String
}

2.单身人士

我需要在项目中的任何地方访问我的结构中的这些属性

在这种情况下,我会使用一个引用图像数组的单例。

例子:

class SharedManager {        
    static let shared = SharedManager()
    private init() {}

    var images: [ImageData]?
}

3.服务助手

让我们编写一个名为的新类APIHelper,它将充当服务助手。在这里,我们将有Alamofire逻辑,所以让我们也改进一下。

  1. 让我们重命名callApi(completion:)为更有意义的东西,比如说,getImages(completion:)
  2. 为方便起见,让我们将其设为类方法。
  3. 也不是提供完成闭包(String, String),而是让它提供[ImageData]?;即ImageData模型数组。
    • 以便稍后在应用程序中轻松访问
    • 如果 url 无效或请求/解析失败,此数组是可选的(只是保持简单)

class APIHelper {

    class func getImages(completion: @escaping ([ImageData]?)->Void) {
        guard let url = URL(string: "https://alodjinha.herokuapp.com/categoria")
            else {
                completion(nil)
                return
        }

        Alamofire
            .request(url)
            .responseJSON { (response) in
                switch response.result {
                case .success(_):
                    do {
                        let myImages = try JSONDecoder().decode(Description.self,
                                                                from: response.data!)
                        completion(myImages.data)
                    }
                    catch {
                        print(error)
                        completion(nil)
                    }
                case .failure(let error):
                    print(error)
                    completion(nil)
                }
        }
    }

}

4.在单例中设置数组

调用getImages(completion:)一次设置SharedManager.shared.images如下:

APIHelper.getImages { (imageData) in
    print(imageData)
    SharedManager.shared.images = imageData
}

5. 用法

现在您应该可以SharedManager.shared.images随时随地访问图像数组(当然在您的应用范围内)

只是您的基本数组处理逻辑,但这里有几个示例:

  • 遍历它们:

    for imageData in SharedManager.shared.images ?? [] {
        print(imageData)
    }
    
  • 访问特定索引处的图像

    let imageIndex = 1
    let imageURL = SharedManager.shared.images?[imageIndex].urlImagem
    print(imageURL)
    
  • 查找具有特定 id 的图像:

    let imageIDToFind = 7
    let foundImage = SharedManager.shared.images?.first { $0.id == imageIDToFind }
    print(foundImage)
    

推荐阅读