Search code examples
jsonswiftalamofirensmutabledictionary

Swift NSMutableDictionary parsing json fails


I have some weird parsing problems with NSMutableDictionary and Alamofire json response.

Alamofire.request(.POST, "\(Constants.apiUrl)/get_stuff", parameters: mapData, encoding:.JSON)
    .responseJSON { response in

        switch response.result {
        case .Success(let data):
            let info = data as! NSMutableDictionary

            self.deleteCategoryFromCoreData()

            if let categoryArray = info["category"] as? NSArray{
                for var i = 0; i < categoryArray.count; i++ {
                    self.categoryID = categoryArray[i]["id"] as? Int  <-- error here
                    self.categoryName = categoryArray[i]["name"] as? NSString
                    self.saveCategoryDataToCoreData()
                }
            }

I dont know why this fails:

(lldb) po categoryArray[i]["id"]
2016-05-23 20:59:56.892 MyProject[9799:5005782] -[__NSCFNumber length]: unrecognized selector sent to instance 0xb000000000000013
error: Execution was interrupted, reason: internal ObjC exception breakpoint(-3)..
The process has been returned to the state before expression evaluation.

but this does not fail:

(lldb) po categoryArray[i]["name"]
▿ Optional<String>
  - Some : "Animals"

Here is the data:

(lldb) po categoryArray[i]
▿ 2 elements
  ▿ [0] : 2 elements
    - .0 : id
  ▿ [1] : 2 elements
    - .0 : name
    - .1 : Animals

Why can't I access "id" key ? I cant parse json like this? I was told to try SwiftyJSON, this way not possible at all. All this problem happened after I updated to Xcode 7.3 and cocoapods 1.0.0.


Solution

  • Foundation collection types don't contain type information and the mutable versions NSMutableArray and NSMutableDictionary aren't related to the Swift counterparts at all.

    Use Swift native types for everything

    Alamofire.request(.POST, "\(Constants.apiUrl)/get_stuff", parameters: mapData, encoding:.JSON)
      .responseJSON { response in
    
        switch response.result {
        case .Success(let data):
          let info = data as! [String:AnyObject]
    
          self.deleteCategoryFromCoreData()
    
          if let categoryArray = info["category"] as? [[String:AnyObject]] {
            for category in categoryArray {
              self.categoryID = category["id"] as? Int
              self.categoryName = category["name"] as? String
              self.saveCategoryDataToCoreData()
            }
          }
    

    If you still get the error than the value for key id is a string

    if let id = category["id"] as? String {  
       self.categoryID = Int(id)
    }
    

    PS: Consider that you assign all values in the repeat loop to the same variables categoryID and categoryName respectively, that means the value will be overwritten in each iteration.