Search code examples
swiftnsxmldocument

Extra argument error when initializing NSXMLDocument


I'm trying to create an NSXMLDocument in Swift, but I'm getting a "Extra argument 'contentsOfURL' in call when I try to create my NSXMLDocument, here's my code :

var url = NSURL(string: "http://api.openweathermap.org/data/2.5/weather?q=\(self.cityField.stringValue)&mode=xml")
var category = NSXMLDocumentContentKind.XMLKind.rawValue
var error: NSError? = NSError()

var document = NSXMLDocument(contentsOfURL: url, options: category, error: &error)

What am I doing wrong ? Thank you.

EDIT : Actually, replacing the initialisation with this :

var document = NSXMLDocument(contentsOfURL: url!, options: kNilOptions, error: &error)

Works, it was first of all the options parameter that was problematic (and also I had to unwrap the url), but now, I'm not getting how to select a specific option if I want to ? What was the problem here ?


Solution

  • Check the type inference for url. (You can do this by option-clicking the variable name anywhere it's used.) You'll find it's of type NSURL? (aka Optional<NSURL>), not NSURL. The NSXMLDocument initializer init?(contentsOfURL:options:error:) requires a non-optional url, so your invocation of that initializer fails type-checking... and then produces a bogus error message.

    (Because it failed the type check, it assumes you're trying to call a different initializer... if that were so, your problem would indeed be that you have the wrong arguments. Might be worth filing a bug about.)

    You get an optional out of your NSURL(string:) invocation because that initializer is failable. If you pass a string that is not a valid URL, that initializer returns nil instead of a valid NSURL instance. Swift is pretty serious about making sure you're aware of and correctly handling possible nils in your code, because otherwise they can cause problems for your app.

    Your solution of force-unwrapping the optional (by passing url! to NSXMLDocument) "works" in that it satisfies the compiler: you've made sure that the value being passed to NSXMLDocument is of non-optional NSURL type. But you haven't really handled the possible nil — if your url is really nil, your app will crash on that line. It's safest to test optionals for nil before using them — and you really ought to do that in this case because the contents of your string can change at runtime, possibly creating a bogus URL.

    Besides that, you have a type mismatch on the options parameter, too: The raw type of the NSXMLDocumentContentKind enum is UInt, but the type expected by that parameter is Int. You can convert it with Int(NSXMLDocumentContentKind.XMLKind.rawValue). (This one is definitely worth filing a bug about — Apple's interfaces should make sure the enum and initializer types match.)


    Finally, an unrelated tip: You're using var for everything, but you're (as far as you've shown) not ever changing what your variables point to. Use let for things that don't change, like url, category, and probably document (remember, you can have a constant reference to a mutable object). This lets the compiler help you make sure your code is correct, and can (theoretically at least) help it generate optimized code at build time, too.