29

I keep getting an error of "ambiguous use of subscript," in my Swift code. I don't know what's causing this error. It just randomly popped up. Here's my code:

if let path = NSBundle.mainBundle().pathForResource("MusicQuestions", ofType: "plist") {
    myQuestionsArray = NSArray(contentsOfFile: path)
}

var count:Int = 1
let currentQuestionDict = myQuestionsArray!.objectAtIndex(count)

if let button1Title = currentQuestionDict["choice1"] as? String {
    button1.setTitle("\(button1Title)", forState: UIControlState.Normal)
}

if let button2Title = currentQuestionDict["choice2"] as? String {
    button2.setTitle("\(button2Title)", forState: UIControlState.Normal)
}

if let button3Title = currentQuestionDict["choice3"] as? String {
    button3.setTitle("\(button3Title)", forState: UIControlState.Normal)
}
if let button4Title = currentQuestionDict["choice4"] as? String {
    button4.setTitle("\(button4Title)", forState: UIControlState.Normal)
}

if let question = currentQuestionDict["question"] as? String!{
    questionLabel.text = "\(question)"
}
kriskendall99
  • 547
  • 1
  • 4
  • 14
  • Do you know what is **Subscripts**? If not, subscripts is a shortcut to access to a element of a collection. Take a look at [this](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html) By the way, could you post the type of your `currentQuestionDict` to understand the context. – awph Nov 11 '15 at 00:21
  • The type? It's basically just an NSDictionary filled with strings. – kriskendall99 Nov 11 '15 at 00:40
  • Do not say what it is "basically". Every Swift variable has a declaration which gives it a specific type. _Show the declaration_ of `currentQuestionDict`. The entire answer to your question depends upon that declaration. To hide it is silly: it _is the answer_. Show it. – matt Nov 11 '15 at 01:00
  • Isn't `let currentQuestionDict = myQuestionsArray!.objectAtIndex(count)` the declaration? – kriskendall99 Nov 11 '15 at 01:02
  • Good, I think that explains it. – matt Nov 11 '15 at 01:14

3 Answers3

36

The problem is that you are using NSArray:

myQuestionsArray = NSArray(contentsOfFile: path)

This means that myQuestionArray is an NSArray. But an NSArray has no type information about its elements. Thus, when you get to this line:

let currentQuestionDict = myQuestionsArray!.objectAtIndex(count)

...Swift has no type information, and has to make currentQuestionDict an AnyObject. But you can't subscript an AnyObject, so expressions like currentQuestionDict["choice1"] cannot compile.

The solution is to use Swift types. If you know what currentQuestionDict really is, type it as that type. At the very least, since you seem to believe it is a dictionary, make it one; type it as [NSObject:AnyObject] (and more specific if possible). You can do this in several ways; one way is by casting when you create the variable:

let currentQuestionDict = 
    myQuestionsArray!.objectAtIndex(count) as! [NSObject:AnyObject]

In short, never use NSArray and NSDictionary if you can avoid it (and you can usually avoid it). If you receive one from Objective-C, type it as what it really is, so that Swift can work with it.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    Excellent. Even more important, though, is to understand what I've said. – matt Nov 11 '15 at 01:33
  • There is something I'm a bit confused about in your answer. You said that you can't subscript an AnyObject, but after you wrote ` myQuestionsArray!.objectAtIndex(count) as! [NSObject:AnyObject]`, the app ran successfully. – kriskendall99 Nov 11 '15 at 01:45
  • Because after that there is no AnyObject in this story. We cast it to an `[NSObject:AnyObject]`, aka a dictionary - and that is something you can subscript. – matt Nov 11 '15 at 02:21
  • Oh. I think I understand what you did now. – kriskendall99 Nov 11 '15 at 02:22
  • You might want to read my book about Swift: http://www.apeth.com/swiftBook/ch04.html#_casting – matt Nov 11 '15 at 02:37
  • *NSArray has no type information about its elements.* <-- do you mean because `NSArray` is coming from Foundation, Swift doesn't know of it and so when passed into Swift. It will *automatically* be converted to `AnyObject`. As a result obviously we must be downcast `AnyObject` to `Array`? – mfaani Jan 17 '17 at 13:11
  • @Honey No, I don't mean that. – matt Jan 17 '17 at 16:37
  • Then what did you mean? :/ – mfaani Jan 17 '17 at 16:41
  • @Honey I meant exactly what I said, no more no less. If you have a different / related question, you know what to do. :) – matt Jan 17 '17 at 16:42
7

["Key"] has causing this error. New Swift update, you should use objectForKey to get your value. In you case just change the your code to ;

if let button1Title = currentQuestionDict.objectForKey("choice1") as? String {
    button1.setTitle("\(button1Title)", forState: UIControlState.Normal)
}
emresancaktar
  • 1,507
  • 17
  • 25
3

This is the code I used to solve the error:

    let cell:AddFriendTableViewCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! AddFriendTableViewCell

    let itemSelection = items[indexPath.section] as! [AnyObject] //'items' is an array of NSMutableArrays, one array for each section

    cell.label.text = itemSelection[indexPath.row] as? String

Hope this helps!

Baylor Mitchell
  • 1,029
  • 1
  • 11
  • 19