Alamofire и ObjectMapper в TableView в Swift - PullRequest
       234

Alamofire и ObjectMapper в TableView в Swift

0 голосов
/ 07 августа 2020

Я новичок в swift и пытаюсь получить json из api и показать его 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)
  }
 }    
}
}

Я попытался распечатать переменную устройства после

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

и показывает мне

Optional([ProjectName.Devices])

Я попытался распечатать данные ответа json и запрос был успешным, но не смог добавить его в tableview. Что мне делать, чтобы решить эту проблему? Не знаю, что делаю не так.

Ответы [ 2 ]

0 голосов
/ 07 августа 2020

Вам не хватает главного объекта. Добавьте этот класс в дополнение к классу вашего устройства.

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
0 голосов
/ 07 августа 2020

Прежде всего - как всегда - поскольку библиотеки Swift 4, такие как ObjectMapper и SwiftyJSON, устарели в пользу встроенного эффективного протокола Codable. Избегайте руководств, в которых предлагаются устаревшие библиотеки.

Что касается вашей ошибки, вы игнорируете объект root, объект с ключами success, user_id и devices.

Это решение с использованием Decodable

  • Drop SwiftyJSON и ObjectMapper

  • Замените структуры на

      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 возвращает необработанные данные, а keyDecodingStrategy преобразует ключи snake_cased в camelCased элементы структуры и logoUrl декодируется как URL

  • Наконец, переименуйте массив источника данных в

      var devices = [Device]()
    

    и удалите все вопросительные знаки после devices

...