我有一个实现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()
完成块,即使它位于某个函数内部也不会被释放。
你需要将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
中的清理步骤,从类的存储集合中删除实例,这样就不会有未使用的实例。
你需要确保你的parser
物体留在身边。现在,一旦someFunc
结束,它就会消失。您可能希望将parser
声明为类级变量。