Swift Subscript Error

2019-07-16 01:43发布

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

        }

1条回答
萌系小妹纸
2楼-- · 2019-07-16 02:16

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!)
查看更多
登录 后发表回答