2

I'm facing an issue where i cannot get the responseData from XMLMapper (objectmapper) to a UITableView. Tableview shows 5 empty cells. Could anyone help me out on this issue?

I'm trying to accomplish a tableview where the IDNR (String) is displayted as label and the Validity is displayed as DetailTextView

best regards,

Patrick

class PersonDetailsView: UITableViewController {
    
    let redirector = Redirector(behavior: .doNotFollow)
    let RequestUrl = "https://apiurlexample.com/api" 
    var personID:String = ""
    
    var schedules: [cardResult]?
    @IBOutlet weak var tableViewData: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        GetCardNumbers()
    }
    
    class cardResult: XMLMappable {
        
        var nodeName: String!
        
        var error: String?
        var cardrowset: cardRowset?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            error <- map.attributes["error"]
            cardrowset <- map["ROWSET"]
        }
    }
    //
    
    class cardRowset: XMLMappable {
        var nodeName: String!
        
        var cardrows: [cardRow]?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            cardrows <- map["ROW"]
        }
    }
    
    class cardRow: XMLMappable {
        var nodeName: String!
        
        var rcn: String?
        var valid: String?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            rcn <- map["IDNR"]
            valid <- map["VALIDITY"]
        }
    }
    
    func GetCardNumbers() {
        
        //
        class personDetails: XMLMappable {
            var nodeName: String!
            var sql: String?
            
            init() {}
            
            required init?(map: XMLMap) {}
            
            func mapping(map: XMLMap) {
                sql <- (map["sql"], XMLCDATATransform())
            }
        }
        
        let persondetails = personDetails()
        persondetails.nodeName = "query"
        persondetails.sql = "select IDNR, Validity from accesskey WHERE personid=\(personID)"
        
        
        AF.request(RequestUrl, method: .post, parameters: persondetails.toXML(), encoding: XMLEncoding.default)
            .redirect(using: redirector)
            .responseXMLObject { (response: DataResponse<cardResult, AFError>) in
                
                
                switch response.result {
                
                case .success(let value):
                    
                    debugPrint(value)
                    print("AF-Success")
                    
                case .failure(let error):
                    
                    print("AF-Error")
                    print(error)
                    
                }
            }
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // return the number of rows
        return 5
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let person = schedules?[indexPath.row].cardrowset?.cardrows
        cell.textLabel?.text = person?[indexPath.row].valid

        return cell
    }
  • Aren't you just missing a tableViewData.reloadData() after receiving the xml data? – Nerkatel Jan 05 '21 at 09:28
  • I'm receiving a fatal error when reloading the data: Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value – patrickb100 Jan 05 '21 at 09:43
  • pretty sure that's because of the fixed number of cells (return 5) while you may not always have data to display 5 rows. It should be something along `return schedules?.count ?? 0` – Nerkatel Jan 06 '21 at 10:42

1 Answers1

0

First of all, it is always better to follow Swift's API Design Guidelines:

Follow case conventions. Names of types and protocols are UpperCamelCase. Everything else is lowerCamelCase.

Also, to display, in your UITableView, the array of CardRow elements you need to hold that array inside your view controller. Instead of that you are declaring an array of CardResult elements which is not right because there is only one CardResult object.

That being said, your view controller should be like this:

class PersonDetailsView: UITableViewController {
    
    let redirector = Redirector(behavior: .doNotFollow)
    let requestUrl = "https://apiurlexample.com/api"
    var personID: String = ""
    
    var cardRows: [CardRow] = []
    @IBOutlet weak var tableViewData: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        getCardNumbers()
    }
    
    class CardResult: XMLMappable {
        var nodeName: String!
        
        var error: String?
        var cardrowset: CardRowset?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            error <- map.attributes["error"]
            cardrowset <- map["ROWSET"]
        }
    }
    
    class CardRowset: XMLMappable {
        var nodeName: String!
        
        var cardrows: [CardRow]?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            cardrows <- map["ROW"]
        }
    }
    
    class CardRow: XMLMappable {
        var nodeName: String!
        
        var rcn: String?
        var valid: String?
        
        required init?(map: XMLMap) {}
        
        func mapping(map: XMLMap) {
            rcn <- map["IDNR"]
            valid <- map["VALIDITY"]
        }
    }
    
    func getCardNumbers() {
        class PersonDetails: XMLMappable {
            var nodeName: String!
            var sql: String?
            
            init() {}
            
            required init?(map: XMLMap) {}
            
            func mapping(map: XMLMap) {
                sql <- (map["sql"], XMLCDATATransform())
            }
        }
        
        let persondetails = PersonDetails()
        persondetails.nodeName = "query"
        persondetails.sql = "select IDNR, Validity from accesskey WHERE personid=\(personID)"
        
        
        AF.request(requestUrl, method: .post, parameters: persondetails.toXML(), encoding: XMLEncoding.default)
            .redirect(using: redirector)
            .responseXMLObject { (response: DataResponse<CardResult, AFError>) in
                switch response.result {
                case .success(let value):
                    debugPrint(value)
                    print("AF-Success")
                    
                    self.cardRows = value.cardrowset?.cardrows ?? []
                    self.tableView.reloadData()
                case .failure(let error):
                    print("AF-Error")
                    print(error)
                }
            }
    }
    
    // numberOfSections(in:) doesn't actually needed here since by default UITableView has one section
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Here you need to return the count of the cardRows array
        return cardRows.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let person = cardRows[indexPath.row]
        cell.textLabel?.text = person.valid

        return cell
    }
}
gcharita
  • 7,729
  • 3
  • 20
  • 37
  • Hi @Gcharita, thanks for your reply. this results on a fatal error on the indexPath.row *thread 1: Fatal error: index out of range. – patrickb100 Jan 05 '21 at 12:45
  • @patrickb100 make sure that you return the `count` of the `cardRows` array in `tableView(_:numberOfRowsInSection:)` function. I think that this is your issue. – gcharita Jan 05 '21 at 14:32
  • Thank you so much! the issue is solved now – patrickb100 Jan 05 '21 at 18:37