import Foundation class Parse { class func parse(stream: NSInputStream) { return Parser().parse(stream) } class Parser: NSObject,NSXMLParserDelegate { func parse(stream: NSInputStream) { let XMLParser = NSXMLParser(stream: stream) let delegate = XMLParserDelegate() XMLParser.delegate = delegate XMLParser.parse() } class XMLParserDelegate: NSObject,NSXMLParserDelegate { func parser( parser: NSXMLParser,didStartElement elementName: String,namespaceURI: String?,qualifiedName qName: String?,attributes attributeDict: [NSObject : AnyObject]) { NSLog("Parsing!") } } } }
当我尝试使用Swift的可见性功能时会出现问题.特别是,我不想让Parser类对其他文件可见(因为它没有理由可见).如果我通过私有类Parser声明它…但是,代码停止工作!解析器:didStartElement:namespaceURI:qualifiedName:attributes:不再被调用!
这一切对我来说都很奇怪,而不像它在任何其他语言中如何运作.因此,我觉得以下两件事之一必须是真的:
> Swift的命名空间系统充其量是奇怪的.更明显的是,它似乎对我不利.
>斯威夫特很好,我只是在做一些非常愚蠢的事情!如果是这样,那就太好了!请让我知道它是什么!
感谢大家的帮助!
编辑:这是一个略微修剪的版本.和以前一样,代码工作正常,直到Parser类被标记为private:
import Foundation class Parse { class func parse(stream: NSInputStream) { return Parser().parse(stream) } } class Parser: NSObject,NSXMLParserDelegate { func parse(stream: NSInputStream) { let XMLParser = NSXMLParser(stream: stream) XMLParser.delegate = self XMLParser.parse() } func parser( parser: NSXMLParser,attributes attributeDict: [NSObject : AnyObject]) { NSLog("Parsing!") } }
解决方法
optional func parser(_ parser: NSXMLParser,namespaceURI namespaceURI: String,qualifiedName qualifiedName: String,attributes attributeDict: [NSObject : AnyObject])
由于它是可选的,因此NSXMLParser中必须有一个doRespondToSelector()调用.如果底层类是私有的,那么函数会失败也就不足为奇了. (鉴于它与动态ObjC调用的交互,如果它起作用也不会令人震惊;但是这两种方法都不应该被认为是破坏的,你所描述的更符合你所要求的;这些方法是私有的.)
这里正确的答案是XMLParserDelegate需要公开以及NSXMLParserDelegate的实现.解析器不必公开,任何非协议方法都不需要公开.但是如果你想让它调用它们,NSXMLParser需要能够看到它的委托方法.
更令人惊讶的是,这不是编译器错误.
编辑:虽然我仍然感到惊讶,这不会产生编译错误(我觉得这可能是一个错误),关键的发现是私人意味着私人.这意味着其他文件无法看到该方法,因此respondsToSelector()将失败.为了以更简单的形式证明这一点:
main.swift
import Foundation private class Impl : NSObject,P { func run() { println("Running") } } let c = Container(p: Impl()) c.go()
more.swift
import Foundation @objc internal protocol P: NSObjectProtocol { optional func run() } // Change internal to private to see change internal struct Container { let p: P func go() { println(p.dynamicType) // Impl for internal,(Impl in ...) for private if p.respondsToSelector(Selector("run")) { p.run!() // if run is internal or public } else { println("Didn't implement") // if run is private } // Or the Swiftier way: if let run = p.run { run() // if run is internal or public } else { println("Didn't implement") // if run is private } } }
要查看有关其原因的更多详细信息,我们可以查看p.dynamicType.如果p是内部的,那么我们看到它的类型是Impl.如果它是私有的,我们看到它的类型是(Impl in _9F9099C659B8A128A78BAA9A7C0E0368).私有化使他们的类型和内部结构变得私密.
私人只是隐藏内部而不是内部.它会影响运行时,而不仅仅是编译时.
我想的越多,我就越明白它为什么不能给我们编译错误.使用私有类实现内部协议是合法的.它横向移动的地方是我们将它作为参数传递给另一个访问区域然后尝试动态地内省它.答案是“不要那样做”.
有可能在未来发生变化.见https://devforums.apple.com/message/1073092#1073092.它值得提出作为bug报告,但我仍然不认为它是一个bug;它肯定是有意的行为.