【问题标题】:Alamofire and ObjectMapper to TableView in SwiftSwift 中的 Alamofire 和 ObjectMapper 到 TableView
【发布时间】:2020-11-27 15:16:45
【问题描述】:

我是 swift 新手,我试图从 api 获取 json 并将其显示给 UITableView,但它不会显示。

这是json:

{
    "success": true,
    "user_id": "somestringhere",
    "devices": [
        {
            "id": "somestringhere",
            "source": "somestringhere",
            "source_text": "somestringhere",
            "logo_url": "somestringhere",
            "is_connected": "0"
        },
        {

用于映射 json 数据:

import Foundation
import ObjectMapper

class Devices: Mappable {
required init?(map: Map) {
}

    func mapping(map: Map) {
        id<-map["id"]
        source<-map["source"]
        sourceText<-map["source_text"]
        logo<-map["logo_url"]
        isConnected<-map["is_connected"]  
    }
   
    var id : String?
    var source : String?
    var sourceText : String?
    var logo : String?
    var isConnected : Bool?
    
}

我的控制器:

import Foundation
import UIKit
import SwiftyJSON
import Alamofire
import ObjectMapper

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    var devices : [Devices]?

    override func viewDidLoad() {
        super.viewDidLoad()
      
        tableView.register(HomeTableViewCell.nib(), forCellReuseIdentifier: HomeTableViewCell.identifier)
        tableView.delegate = self
        tableView.dataSource = self
        loadData()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return devices?.count ?? 0
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.identifier, for: indexPath) as! HomeTableViewCell
        
        cell.setup(title: "\(devices?[indexPath.row].sourceText)", iconLink: "\(devices?[indexPath.row].logo)")
        return cell
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 120
    }
    
    func loadData(){
        let base = Config().base
        let endPoint = Config.EndPoint()
        let patientId = User().id
            
                let url = base + endPoint.showDevices
                let header: HTTPHeaders = [
                    "Content-Type": "application/json",
                ]
                let params: Parameters = [
                    "patient_id" : patientId
                ]
                
                let code = Code(id: id)
                AF.request(url, method: .get, parameters: params, encoding: URLEncoding.default, headers:header).validate()
                    .response{ (response) in
                        switch response.result {
                        case .success(let value):
                            let json = JSON(value)
                           
                          self.devices = Mapper<Devices>().mapArray(JSONString: json.rawString()!)
            self.tableView.reloadData()
                           
                         case .failure(let error):
                            print(error)
  }
 }    
}
}

我尝试在 Mapper 之后打印设备变量

self.devices = Mapper<PatientDevices>().mapArray(JSONString: json.rawString()!)
print(self.devices)

给我看

Optional([ProjectName.Devices])

我尝试打印 json 响应数据并请求成功,但是我无法将其添加到 tableview。 我应该怎么做才能解决这个问题? 我不知道我做错了什么。

【问题讨论】:

    标签: ios json swift alamofire objectmapper


    【解决方案1】:

    首先——一如既往——因为像ObjectMapperSwiftyJSON这样的Swift 4库已经过时了,取而代之的是内置的、高效的Codable协议。避免推荐那些过时的库的教程。

    关于您的错误,您忽略了根对象,即带有键 successuser_iddevices 的对象。

    这是使用Decodable的解决方案

    • 删除SwiftyJSONObjectMapper

    • 将结构替换为

        struct Root : Decodable {
            let success : Bool
            let userId : String
            let devices : [Device]
        }
      
        struct Device : Decodable {
            let id : String
            let source : String
            let sourceText : String
            let logoUrl : URL
            let isConnected : String // this value is String, not Bool
        }
      
    • loadData 替换为

        func loadData(){
            let base = Config().base
            let endPoint = Config.EndPoint()
            let patientId = User().id
      
            let url = base + endPoint.showDevices
            let header: HTTPHeaders = [
                "Content-Type": "application/json",
            ]
            let params: Parameters = [
                "patient_id" : patientId
            ]
      
            let code = Code(id: id)
            AF.request(url, parameters: params, headers:header).validate()
                .responseData { (response) in
                    switch response.result {
                        case .success(let data):
                            do {
                                let decoder = JSONDecoder()
                                decoder.keyDecodingStrategy = .convertFromSnakeCase
                                let result = try decoder.decode(Root.self, from: data)
                                self.devices = result.devices
                                self.tableView.reloadData()
                            } catch { print(error) }
      
                        case .failure(let error):
                            print(error)
                    }
            }
        }
      

      Alamofire 响应返回原始数据,keyDecodingStrategysnake_cased 键转换为 camelCased 结构成员,logoUrl 被解码为 URL

    • 最后将数据源数组重命名为

        var devices = [Device]()
      

      并删除devices之后的所有问号

    【讨论】:

      【解决方案2】:

      您缺少主要对象。除了您的 Device 类之外,添加此类。

      import Foundation
      import ObjectMapper
      
      class Response: Mappable {
      
          required init?(map: Map) {
          }
      
          func mapping(map: Map) {
              success<-map["success"]
              user_id<-map["user_id"]
              devices<-map["devices"]
          }
      
          var success : Bool?
          var user_id : String?
          var devices: [Device]?
      
      }
      

      同时创建一个新变量来映射主对象

      var response: Response?
      

      改变

      self.devices = Mapper<Devices>().mapArray(JSONString: json.rawString()!)
      

      self.response = Mapper<Response>().map(JSONString: json.rawString()!)
      self.devices = self.response.devices
      

      【讨论】:

      • 谢谢,我将从现在开始对我的项目执行此操作。
      猜你喜欢
      • 2018-08-25
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2018-02-18
      • 2018-12-23
      • 1970-01-01
      • 2017-08-04
      相关资源
      最近更新 更多