I am trying to implement an NSXMLParserDelegate in Swift but I am having issues using the attributes dictionary in some of the delegate methods. For instance, in parser:didStartElement:
:
func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {
trying to access attributeDict values like:
if self.feedType == FeedType.RSS {
self.insideLink = true
} else {
if (String(attributeDict["rel"]) == "alternate") && (String(attributeDict["type"]) == "text/html") {
self.link = String(attributeDict["href"])
self.insideLink = false
self.doneWithLink = true
}
}
I get an error message: "'String' is not convertible to 'FeedType'".
enum FeedType:String {
case ATOM = "feed"
case RSS = "rss"
}
class FeedParser:NSObject, NSXMLParserDelegate {
var feedType:FeedType?
Is an error. Same for a dozen other variations on the theme... any insights?
I guess the question is how to properly use the key / value pairs in attributeDict
which are of type [NSObject: AnyObject]
?
Looks like you might have a bogus error message: I'd recommend filing a bug.
You're right: this looks like the root of the problem. The solution is not to construct a
String
from the dictionary lookup, but to (conditionally) cast toString
. That is, rather than try to create a newString
from a reference of indeterminate (and optional) type, ask Swift if that reference is actually to something that can be interpreted as aString
:That gets you an optional, both because
attributeDict
might not contain a value for the keyrel
, and because a conditional cast can fail (attributeDict["rel"]
might be a value of a different type). Because you need to check two conditional casts and their unwrapped values, you could end up with a lot of force-unwrap operators (!
) or deeply nestedif-let
blocks... that'd get ugly real fast.Instead, you can take advantage of the fact that
Optional
is an enum. Its definition looks something like this:With that, you can use pattern matching to do the lookup, cast, unwrap and test safely and concisely:
Note that on the "harvest link" step you'll still need to conditionally cast and unwrap the
attributeDict["href"]
lookup. You could do that by nesting anif-let
construct in thatcase
, or by adding a third lookup to theswitch
tuple.By the way, all the
self.
notation is unnecessary in Swift (unless you're in a closure or need to disambiguate method parameters from instance properties).