允许完成处理程序比创建它的本地范围更长

问题描述 投票:1回答:2

我有一个实现XMLParserDelegate协议的类,在初始化过程中,它获取一个字符串和一个完成处理程序作为参数。我正在尝试在解析字符串后调用完成处理程序,但由于类的重新分配而未达到XMLParserDelegate方法。

class MyXMLParser: NSObject, XMLParserDelegate {

private (set) var parser: XMLParser?
private (set) var completion: ((String?) -> Void)?

public init(_ xml: String, _ completion: @escaping ((String?) -> Void)) {
    let data = xml.data(using: String.Encoding.utf8)
    self.parser = XMLParser(data: data ?? Data())
    self.completion = completion
    self.parser?.delegate = self
    self.parser?.parse()
}

deinit {
    // Being called before Parser methods
}

// MARK: - Parser delegate methods

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
    // Custom implementation
}

func parserDidEndDocument(_ parser: XMLParser) {
    // Custom implementation
    self.completion?("Test")
}

func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
    self.completion?(nil)
}

}

我用以下方式调用它:

func someFunc() {
    let parser = MyXMLParser(someXMLString) { text in
        // Custom implementation
    }
}

我希望闭包保持活着直到它获得值,而不是在函数内部的局部作用域结束后取消初始化。我想要实现的很好的例子是UIView.animate()完成块,即使它位于某个函数内部也不会被释放。

ios swift memory-management automatic-ref-counting object-lifetime
2个回答
0
投票

你需要将MyXMLParser存储在除局部变量之外的某个地方。就那么简单。

请注意,UIView.animate(...)是一种类方法。这意味着该类在生命周期管理中以某种方式参与其中。

模仿的一个简单选择是稍微改变你的界面,这样你就不用直接创建MyXMLParser,而是要求全班为你做:

class MyXMLParser : NSObject, XMLParserDelegate {

    private static var createdParsers: Set<MyXMLParser> = []

    static func parse(_ xml: String, _ completion: @escaping (String?) -> Void) {
        let newParser = MyXMLParser(xml, completion)
        self.createdParsers.insert(newParser)
    }

    private static func parserDidEndParsing(_ parser: MyXMLParser) {
        self.createdParsers.remove(parser)
    }

    private let parser: XMLParser
    private let completion: (String?) -> Void

    private init(_ xml: String, _ completion: @escaping (String?) -> Void) {
        // Same as existing code
    }

    //...

    func parserDidEndDocument(_ parser: XMLParser) {
        //...
        MyXMLParser.parserDidEndParsing(self)
    }
}

这里一个单独的解析器由它的类拥有,你可以通过调用MyXMLParser.parse(myXmlString) { (text) in /* whatever */ }来创建一个。重要的是要注意parserDidEndDocument中的清理步骤,从类的存储集合中删除实例,这样就不会有未使用的实例。


0
投票

你需要确保你的parser物体留在身边。现在,一旦someFunc结束,它就会消失。您可能希望将parser声明为类级变量。

© www.soinside.com 2019 - 2024. All rights reserved.