6

Trying to find the title of each book:

var error: NSError?
    let path = NSBundle.mainBundle().pathForResource("books", ofType: "json")
    let jsonData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)
    let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as NSDictionary
    let books = jsonDict["book"]

    var bookTitles:[String]

    //for bookDict:Dictionary in books {
    //    println("title: \(bookDict["title"])")
    //}

When I uncomment those last three lines, all hell breaks loose in Xcode6 beta3 - all text turns white, I get constant "SourceKitService Terminated" and "Editor functionality temporarily limited" popups, and I get these helpful build errors:

<unknown>:0: error: unable to execute command: Segmentation fault: 11
<unknown>:0: error: swift frontend command failed due to signal

I have seriously offended the compiler here. So what is the correct way to iterate through the array of dictionaries and find the "title" property of each dict?

soleil
  • 12,133
  • 33
  • 112
  • 183
  • 3
    Don't ignore the error returns, professionalism requires the error paths to be handled. – zaph Jul 21 '14 at 21:54
  • `println()` `jsonData`, `jsonDict`, `books`. Add an error var to `NSData.dataWithContentsOfFile`. Check the return values and `println()` any error vars if there is an error. Not that `println()` is sufficient error handling. Steeping through with the debugger is also a useful debugging process. – zaph Jul 21 '14 at 21:57

1 Answers1

16

You're having issues because Swift is unable to infer that books is an iterable type. If you know the type of the array going in, you should be explicitly casting to this type. If for example, the array should be an array of dictionaries which have strings as objects and keys, you should do the following.

if let books = jsonDict["book"] as? [[String:String]] {
    for bookDict in books {
        let title = bookDict["title"]
        println("title: \(title)")
    }
}

Also note that you have to remove the subscript dictionary access from the string interpolation because it contains quotation marks. You just have to do it on two lines.

Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
  • Thanks, this is helpful. What if the dictionary has some objects that are String:String and some that are String:Array? In this case for example, the book dictionary could contain a "chapter" key that has an array of chapter dictionaries. – soleil Jul 22 '14 at 02:23
  • 1
    @soleil In that case, you would probably want to use [[String:AnyObject]]. Of course this would mean that you would have to repeat the if let... to check which case you're currently dealing with. – Mick MacCallum Jul 22 '14 at 08:23
  • 3
    If it helps anyone else, the [[String:String]] bit is saying "books is (potentially) an array of dictionaries where the key and value are both strings" or this format which is more familiar to me: Array> – rob5408 Oct 10 '14 at 00:59