【问题标题】:XMLParser Delegate Methods not Called未调用 XMLParser 委托方法
【发布时间】:2019-04-13 19:27:09
【问题描述】:

我正在尝试将 XML 解析器抽象为自定义类以从 VC 运行它。它编译完美,我的错误处理程序显示成功。但是,跳过了实际的委托方法。没有数据被解析。

当我在 VC 上运行它时一切都运行良好,但我现在正试图摆脱意大利面条式代码。

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let parser = XMLParserHelper()
        //try create file for persistent data
        //CreatePlist.createPlist()
        parser.runParser()
    }
}

class XMLParserHelper:  NSObject, XMLParserDelegate {
    //list type variables to hold XML values (update list base on XML structure):
    static var station: String = ""
    static var latitude: String = ""
    static var longitude: String = ""
    private static var code: String = ""
    private static var id: String = ""

    //reusable method type veriales (do not touch)
    static var strXMLData:String = ""
    static var currentElement:String = ""
    static var passData:Bool=false
    static var passName:Bool=false
    static var xmlParser = XMLParser()

    //parser methods
    func runParser(){
        let xmlPath = Bundle.main.url(forResource: "station", withExtension: "xml")
        let xmlParser = XMLParser(contentsOf: (xmlPath)!)
        xmlParser?.delegate = self
        let success:Bool = xmlParser!.parse()
        xmlParser?.parse()
        if success {
            print("parse success!")
            print(XMLParserHelper.currentElement)
        } else {
            print("parse failure!")
        }
    }

    private static func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        XMLParserHelper.currentElement=elementName;
        if (elementName=="StationDesc" || elementName=="StationLatitude" || elementName=="StationLongitude" || elementName=="StationCode" || elementName=="StationId" ) {
            if (elementName=="StationDesc") {
                XMLParserHelper.passName=true;
            }
            XMLParserHelper.passData=true;
        }
    }

    private static func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        XMLParserHelper.currentElement="";
        if (elementName=="StationDesc" || elementName=="StationLatitude" || elementName=="StationLongitude" || elementName=="StationCode" || elementName=="StationId" ) {
            if(elementName=="StationDesc") {
                XMLParserHelper.passName=false;
            }
            XMLParserHelper.passData=false;
        }
    }

    private static func parser(_ parser: XMLParser, foundCharacters string: String) {
        if (XMLParserHelper.passName) {
            XMLParserHelper.strXMLData=XMLParserHelper.strXMLData+"\n\n"+string
        }

        if (XMLParserHelper.passData) {
            //ready content for codable struct
            switch XMLParserHelper.currentElement {
            case "StationDesc":
                XMLParserHelper.station = string
            case "StationLatitude":
                XMLParserHelper.latitude = string
            case "StationLongitude":
                XMLParserHelper.longitude = string
            case "StationCode":
                XMLParserHelper.code = string
            case "StationId":
                XMLParserHelper.id = string
                print(string)

            default:
                XMLParserHelper.id = string
            }
        }
    }

    func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
        print("failure error: ", parseError)
    }
}

【问题讨论】:

  • 所有重复的字符串文字让我的眼睛受伤:(
  • 如果 xmlParser 为 nil,则在 runParser 中使用警卫执行致命错误
  • 与您的问题无关,但您不需要在 Swift 中使用 ;,也不需要在 if 语句中使用 ( )

标签: ios swift nsxmlparser


【解决方案1】:

要使XMLParserDelegate 方法起作用,所有方法都必须是非静态、非私有方法。

所以,所有的属性也应该是非静态的。

class XMLParserHelper: NSObject, XMLParserDelegate {

    //list type variables to hold XML values (update list base on XML structure):
    var station: String = ""
    var latitude: String = ""
    var longitude: String = ""
    private var code: String = ""
    private var id: String = ""

    //reusable method type veriales (do not touch)
    var strXMLData: String = ""
    var currentElement: String = ""
    var passData: Bool = false
    var passName: Bool = false

    //parser methods
    func runParser() {
        let xmlURL = Bundle.main.url(forResource: "station", withExtension: "xml")!
        let xmlParser = XMLParser(contentsOf: xmlURL)!
        xmlParser.delegate = self
        let success = xmlParser.parse()
        if success {
            print("parse success!")
            print(currentElement)
        } else {
            print("parse failure!")
        }
    }

    //MARK: XMLParserDelegate methods

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
        currentElement = elementName
        if elementName == "StationDesc"
        || elementName == "StationLatitude"
        || elementName == "StationLongitude"
        || elementName == "StationCode"
        || elementName == "StationId"
        {
            if elementName == "StationDesc" {
                passName = true
            }
            passData = true
        }
    }

    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        currentElement = ""
        if elementName == "StationDesc"
        || elementName == "StationLatitude"
        || elementName == "StationLongitude"
        || elementName == "StationCode"
        || elementName == "StationId"
        {
            if elementName == "StationDesc" {
                passName = false
            }
            passData = false
        }
    }

    func parser(_ parser: XMLParser, foundCharacters string: String) {
        if passName {
            strXMLData = strXMLData+"\n\n"+string
        }

        if passData {
            //ready content for codable struct
            switch currentElement {
            case "StationDesc":
                station = string
            case "StationLatitude":
                latitude = string
            case "StationLongitude":
                longitude = string
            case "StationCode":
                code = string
            case "StationId":
                id = string
                print(string)

            default:
                id = string
            }
        }
    }

    func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
        print("failure error: ", parseError)
    }
}

XMLParser 只需要在parse() 运行时保持,因此您无需将xmlParser 声明为XMLParserHelper 的属性。

【讨论】:

  • OOPer,Gem,它工作得很好——已经为此苦苦挣扎了一段时间,所以看到那些解析器方法被调用真是一种感觉!我想我现在知道哪里出了问题,因为我的自定义类正在调用这些解析方法,所以我假设它们是类型方法而不是实例方法(因此我将它们标记为静态/私有,但由于它们实际上是委托方法,它们不是私有的或键入方法。
  • @FrankFerdinandMcGovern 请不要忘记通过单击最有帮助的答案左侧的复选标记来表明您的问题已得到解决。
  • @maddy,感谢您的提醒和指点,对 SO 来说很新,所以想知道 - 已相应更新
【解决方案2】:

你需要一个强有力的参考

class ViewController: UIViewController{
   var parser:XMLParserHelper!
   override func viewDidLoad() {
     super.viewDidLoad()
     parser = XMLParserHelper()
     parser.runParser()
   }
}

【讨论】:

  • 好答案。如果没有强引用,解析器将在完成其工作之前被解除分配。
  • 这不是问题,因为runParser 不是异步的。
猜你喜欢
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 2015-06-09
  • 2016-07-16
  • 2019-01-04
相关资源
最近更新 更多