swiftuitableviewmappingalamofirexmlmapper

XMLMapper not showing result in UITableView


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
    }

Solution

  • 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
        }
    }