2

I believe it has something to do with optionals, but I'm safely unwrapping sourceURL so I'm still not sure where the error is! I'm trying to access a JSON object's array's dictionary value.

However, I'm still getting the "could not find overload for 'subscript' that accepts the supplied arguments.

It seems simple, but I just can't seem to figure it out!

        var dictTemp: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) as? NSDictionary
        var finalURL: String
        // error line below
        if let sourceURL = dictTemp[0]["source"]["sourceUrl"] as? NSString {
            finalURL = sourceURL as String

        }
6
  • 1
    What type is dictTemp? Commented Jul 25, 2015 at 5:21
  • And by the way, as? NSString ... as String isn't necessary. You can just use as? String. Commented Jul 25, 2015 at 5:22
  • @jtbandes added to the question. Thanks! Commented Jul 25, 2015 at 5:22
  • Did it really? I'm still seeing the error. However, I believe you can use dictTemp[0]?["source"]??["sourceURL"]. Kind of a mouthful. Commented Jul 25, 2015 at 5:26
  • @jtbandes no you're right. sorry I got excited for a second I think xcode was just slow in giving me a new error message. will try that thanks Commented Jul 25, 2015 at 5:26

1 Answer 1

4

NSDictionary accessed from Swift is an interesting beast.

As long as Swift only knows something is an NSDictionary (not a more specific [Key: Value] Swift-style dictionary), you can only retrieve AnyObject?s out of it.

let dictTemp: NSDictionary = // from somewhere...

let step1 = dictTemp[0]  // step1 is an AnyObject?

But then, since you've imported Foundation, you can keep going with a magical subscript operator that works on AnyObject, and checks whether the thing is a dictionary:

let step2 = step1?["source"] // step2 is any AnyObject??

Here's where it gets interesting, because

  • if step1 was a dictionary with a "source" key inside it, step2 will be the corresponding value.
  • if step1 was a dictionary without a "source" key, step2 will be nil — in particular, it's AnyObject??.Some(AnyObject?.None).
  • if step1 was nil (the original dictionary didn't have 0 as a key), or not a dictionary (it had a 0 key with some other kind of value), then step2 will be nil — in particular, AnyObject??.None.

(The distinction between the last 2 cases is mostly unimportant and you shouldn't worry about it, but if you're interested you can see it by using dump).

And of course, we can apply the same principle again:

let step3 = step2??["sourceUrl"] // step3 is AnyObject?? again

Now, binding them all in one if:

if let url = dictTemp[0]?["source"]??["sourceUrl"] as? String {
    // do something with url...
}

Caveat

This type of syntax can be dangerous, since it works with arrays and dictionaries at the same time. What would you expect in these situations?

let dict: NSDictionary = [0: ["source": [3: "result"]]]

dict[0]?["source"]??[3] // returns nil (surprise!)
dict[0]?["source"]??[3 as NSNumber] // returns "result"

let dict2: NSDictionary = [0: ["source": [8, 7, 6, 5, 4]]]

dict2[0]?["source"]??[3] // returns 5
dict2[0]?["source"]??[3 as NSNumber] // returns nil (surprise!)
Sign up to request clarification or add additional context in comments.

2 Comments

Still, why does AnyObject? return a double optional from a subscript while Dictionary? returns a single optional from a subscript? I guess it's just hard to get through my head why it would be that way, besides an oversight by the language designers.
Probably because Dictionary can always be queried for keys, whereas AnyObject may not even be a NSDictionary or NSArray at all. I agree though, it seems weird.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.