2017-07-27 3 views
0

Ich wollte beginnen, meine Android App mit Swift zu schreiben. Die App soll ein xml von einer URL verwenden, um eine Liste von Objekten anzuzeigen.Swift Fehler beim Auslagern einer Methode auf eine statische Methode

Die Analyse und Anzeige in einem UITableViewController funktioniert bereits. Jetzt möchte ich die Analyse in eine statische Klasse auslagern, die ich verwenden kann, wann immer ich die Liste der Objekte erhalten möchte.

Das Problem ist, dass ich einen EXC_BAD_ACCESS Fehler erhalte, wenn ich die ausgelagerte Klasse verwende. Ich denke, das Problem könnte sein, dass ich versuche, auf Speicher zuzugreifen, der bereits freigegeben wurde, aber ich bin mir nicht sicher.

Im Folgenden finden Sie den Code finden können, die ich verwende:

XML (vereinfacht):

<result> 
    <row> 
     <id>1</id> 
     <name>Alpha</name> 
    </row> 
    <row> 
     <id>2</id> 
     <name>Beta</name> 
    </row> 
    <row> 
     <id>3</id> 
     <name>Gamma</name> 
    </row> 
</result> 

XMLHelper.swift (Outsourcing-Klasse, verwendet die ausgelagerte Klasse ToolXMLParserDelegate.swift):

import Foundation 

class XMLHelper : NSObject{ 

    static var baseURL = "{myServerUrl}" // not public for security reasons 
    static var toolListString = "getToolList.php" 

    class func getToolList() -> [Tool]? { 
     var toolList: [Tool] = [] 

     let url = baseURL+toolListString 

     guard let myURL = URL(string: url) else { 
      print("URL not defined properly") 
      return nil 
     } 
     guard let parser = XMLParser(contentsOf: myURL as URL) else { 
      print("Cannot Read Data") 
      return nil 
     } 

     parser.delegate = ToolXMLParserDelegate(toolList: &toolList) 

     if !parser.parse() { //HERE I GET THE ERROR 
      print("Data Errors Exist:") 
      let error = parser.parserError! 
      print("Error Description:\(error.localizedDescription)") 
      //print("Error reason:\(error.localizedFailureReason)") 
      print("Line number: \(parser.lineNumber)") 
     } 

     return toolList 
    } 
} 

ToolXMLParserDelegate.swift:

import Foundation 

class ToolXMLParserDelegate : NSObject, XMLParserDelegate { 

    var tools: [Tool] = [] 
    var eName: String = String() 
    var toolId = String() 
    var toolName = String() 

    init(toolList : inout [Tool]) { 
     self.tools = toolList 
    } 


    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 
     eName = elementName 
     if elementName == "row" { 
      toolId = String() 
      toolName = String() 
     } 
    } 


    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 
     if elementName == "row" { 

      let tool = Tool() 
      tool.id = Int(toolId)! 
      tool.name = toolName 
      tools.append(tool) 
     } 
    } 


    func parser(_ parser: XMLParser, foundCharacters string: String) { 
     let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 

     if (!data.isEmpty) { 
      if eName == "id" { 
       toolId += data 
      } else if eName == "name" { 
       toolName += data 
      } 
     } 
    } 
} 

Tool.swift:

import UIKit 

class Tool: NSObject { 

    var id: Int = Int() 
    var name: String = String() 

    override init() {} 

    init(id: Int, name: String) { 
     self.id = id 
     self.name = name 
    } 

    init(name: String) { 
     self.name = name 
    } 
} 

ToolTableViewController.swift: (verwendet XMLHelper.getToolList())

import UIKit 

class ToolTableViewController: UITableViewController, XMLParserDelegate { 

    var tools: [Tool] = [] 
    var eName: String = String() 
    var toolId = String() 
    var toolName = String() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     tableView.tableFooterView = UIView() // to remove empty cells in the list 
    } 

    override func viewWillAppear(_ animated: Bool) { 
     tools = XMLHelper.getToolList()! 

     // this code piece is working, but i want to outsource it, so i can use it again 
     /* 
     let url = "{myUrl}" // not public for security reason 
     let myURL = URL(string: url) 
     let parser = XMLParser(contentsOf: myURL!)! 
     parser.delegate = self as XMLParserDelegate 
     parser.parse() 
     */ 

     tableView.reloadData()*/ 

     print("view did refresh") 
    } 


    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    // MARK: - Table view data source 

    override func numberOfSections(in tableView: UITableView) -> Int { 
     return 1 
    } 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return tools.count 
    } 


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     //let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) 

    let cellIdentifier = "ToolTableViewCell" // simple TableViewCell with a label 

    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? ToolTableViewCell else { 
     fatalError("The dequeued cell is not an instance of ToolTableViewCell.") 
    } 

    let tool = tools[indexPath.row] 

    cell.labelName.text = String(tool.id)+" "+tool.name 

    return cell 
} 

// MARK: XMLParserDelegate (this code here is only used when the code above is uncommented, it is the same as the code in ToolXMLParserDelegate) 

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 
     eName = elementName 
     if elementName == "row" { 
      toolId = String() 
      toolName = String() 
     } 
    } 

    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 
     if elementName == "row" { 

      let tool = Tool() 
      tool.id = Int(toolId)! 
      tool.name = toolName 

      tools.append(tool) 
     } 
    } 

    func parser(_ parser: XMLParser, foundCharacters string: String) { 
     let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) 

     if (!data.isEmpty) { 
      if eName == "id" { 
       toolId += data 
      } else if eName == "name" { 
       toolName += data 
      } 
     } 
    } 
} 
+0

können Sie Vergangenheit Fehlerprotokoll, ich, was Sie etwas deutlicher verpasst. – Maxime

+0

um Klassenfunktionen statisch zu machen, deklariere die Funktion als 'class func()' {} –

+0

Könntest du die Klasse XMLParser posten? Ich weiß nicht, ob du die Delegiertenklasse richtig verstanden hast –

Antwort

0

Ich habe Es funktioniert jetzt, es sieht so aus als ob ich mit der Referenz vermasselt hätte s.

Hier ist, was ich geändert:

ToolXMLParserDelegate

init(toolList : [Tool]) { //removed inout 
    self.tools = toolList 
} 

XMLHelper

class func getToolList() -> [Tool]? { 
    // not needed anymore 
    //var toolList: [Tool] = [] 

    let baseURL = "https://henkel.simonus.de/approval/xml/" 
    let toolListString = "getToolList.php" 

    let url = baseURL+toolListString 

    guard let myURL = URL(string: url) else { 
     print("URL not defined properly") 
     return nil 
    } 
    guard let parser = XMLParser(contentsOf: myURL as URL) else { 
     print("Cannot Read Data") 
     return nil 
    } 

    // CHANGES 
    let myDelegate = ToolXMLParserDelegate(toolList: []) // pass an empty array 
    parser.delegate = myDelegate 

    if !parser.parse() { 
     print("Data Errors Exist:") 
     let error = parser.parserError! 
     print("Error Description:\(error.localizedDescription)") 
     //print("Error reason:\(error.localizedFailureReason)") 
     print("Line number: \(parser.lineNumber)") 
    } 

    // return the list of the delegate instead of the xmlhelpers toolList 
    return myDelegate.tools 
} 
Verwandte Themen