Josue Gramajo Josue Gramajo - 23 days ago 6
Swift Question

How to execute parser delegate first in UITableViewController in Swift

I am new to swift programming language, i am trying to use the

NSXMLParserDelegate
to parse an
xml
from a
soap
web service connection, the connection is working perfectly:

struct Datos {
let nombre:String
let numero:String
}

var data = [Supervisor_Agencia]()

override func viewDidLoad() {

print("viewload")

var soapMessage = "...The xml message..."

var urlString = "...The web service url..."
var url = NSURL(string: urlString)
var request = NSMutableURLRequest(URL: url!)

request.HTTPMethod = "POST"
request.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding)
request.addValue("...The Host...", forHTTPHeaderField: "Host")
request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.addValue(String(soapMessage.characters.count), forHTTPHeaderField: "Content-Length")
request.addValue("...The SOAP Action...", forHTTPHeaderField: "SOAPAction")

var connection = NSURLConnection(request: request, delegate: self, startImmediately: true)
connection!.start()
if (connection == true) {
var mutableData : Void = NSMutableData.initialize()
}
}


The parser delegate does its job and parses the info:

func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {/*The code*/}
func parser(parser: NSXMLParser, foundCharacters string: String) {/*The code*/}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
print("parser")
cont = cont + 1
data.append(Supervisor_Agencia(nombre: descripcion, numero: resultado))}


The problem is that when i tried to use the array "data" to make the cells i realize that the function parse executes at last, after the method tableView, so i cant use the array because it`s not filled yet:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("cont")
return cont
}


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("cells")
let cell = tableView.dequeueReusableCellWithIdentifier("celda", forIndexPath: indexPath) as UITableViewCell

var dat : Supervisor_Agencia

dat = data[indexPath.row]

cell.textLabel?.text = dat.nombre

return cell
}


I know this because the output order of the "print" is this:

1.viewload 2.cont 3.cells 4.parser

and i need that order be like this:

1.viewload 2.parser 3.cont 4.cells

Can anybody tell me how can i achieve this?

Answer

The problem you're having is that a web request does not come back at a time you can determine. Once your parser function returns the results, call self.tableView.reloadData(), and it will then use data properly to fill in your tableView, calling all the delegates as needed.

Before that happens, the easiest thing to do is to either create a data placeholder that is an empty array, which will then return 0 for number of rows and sections (and therefore you won't have to worry about cellForRowAtIndexPath as it won't be called.