【问题标题】:Swift trouble parsing JSON: Could not cast value of type '__NSCFDictionary' to 'NSArray' errorSwift 解析 JSON 时出现问题:无法将“__NSCFDictionary”类型的值转换为“NSArray”错误
【发布时间】:2015-12-08 20:10:13
【问题描述】:

我是 iOS 开发的新手,在解析来自 API 的 JSON 响应时遇到问题。

这是我的示例 JSON 的样子:

{
"recipe":{
"publisher":"Real Simple",
"f2f_url":"http://food2fork.com/view/39999",
"ingredients":[
    "1 tablespoon olive oil",
    "1 red onion, chopped",
    "2 small yellow squash, cut into 1/2-inch pieces",
    "2 cloves garlic, chopped",
    "1 jalapeo, seeded and thinly sliced",
    "1 kosher salt and black pepper",
    "4 28-ounce can diced tomatoes\n"
],
"source_url":"http://www.realsimple.com/food-recipes/browse-all-recipes/halibut-spicy-squash-tomatoes-00000000006842/index.html",   
"recipe_id":"39999", "image_url":"http://static.food2fork.com/someurl.jpg",
  "social_rank":95.14721536803285,
  "publisher_url":"http://realsimple.com",
  "title":"Halibut With Spicy Squash and Tomatoes"
  }
}

当我打印 JSON(本例中的另一个)时,它看起来像这样:

["recipe": {
    "f2f_url" = "http://food2fork.com/view/20970";
    "image_url" = "http://static.food2fork.com/98113574b0.jpg";
    ingredients =     (
    "1 (170 gram) can crabmeat",
    "125 grams PHILADELPHIA Light Brick Cream Cheese Spread, softened",
    "2 green onions, thinly sliced",
    "1/4 cup MIRACLE WHIP Calorie-Wise Dressing",
    "12 wonton wrappers"
  );
    publisher = "All Recipes";
    "publisher_url" = "http://allrecipes.com";
    "recipe_id" = 20970;
    "social_rank" = "41.83825995815504";
    "source_url" = "http://allrecipes.com/Recipe/Philly-Baked-Crab-Rangoon/Detail.aspx";
    title = "PHILLY Baked Crab Rangoon";
}]

我有一个对象配方,它看起来像这样:

class Recipe {
  struct Keys {
      static let Title = "title"
      static let ImageUrl = "image_url"
      static let Ingredients = "ingredients"
      static let RecipeId = "recipe_id"
  }

  var title : String? = nil
  var id = 0
  var imageUrl : String? = nil
  var ingredients : String? = nil

  init(dictionary : NSDictionary) {
      self.title = dictionary[Keys.Title] as? String
      self.id = dictionary[RecipeDB.Keys.ID] as! Int
      self.imageUrl = dictionary[Keys.ImageUrl] as? String
      self.ingredients = dictionary[Keys.Ingredients] as? String
    }
}

当我尝试解析 JSON 并将其转换为字典时,我收到 Could not cast value of type '__NSCFDictionary' to 'NSArray' 错误

这是我将响应转换为字典并导致错误的方法

func recipiesFromData(data: NSData) -> [Recipe] {

    var dictionary : [String : AnyObject]!

    dictionary = (try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)) 
  as! [String : AnyObject]

    let recipeDictionaries = dictionary["recipe"] as! [[String : AnyObject]]

    let recipies = recipeDictionaries.map() { Recipe(dictionary: $0) }

    return recipies
}

谢谢。

【问题讨论】:

  • 这看起来不像是有效的 JSON。
  • 那不是原始的 JSON。这看起来像是解析后的 JSON 的print。
  • 为什么要将 nsdictionary 转换为 nsarray ?
  • 是的,这是 JSON 的打印,我将编辑我的帖子并给出另一个 JSON 示例

标签: ios json swift parsing


【解决方案1】:

如果这是您的 JSON(单个配方),则解析代码如下所示:

func recipeFromData(data: NSData) -> Recipe {
    let dictionary = (try! NSJSONSerialization.JSONObjectWithData(data, options: [])) as! [String : [String : AnyObject]]

    return Recipe(dictionary: dictionary["recipe"]!)
}

我可能会像这样调整 Recipe 类:

class Recipe {
    struct Keys {
        static let Title = "title"
        static let ImageUrl = "image_url"
        static let Ingredients = "ingredients"
        static let RecipeId = "recipe_id"
    }

    var title: String?
    var id: Int
    var imageUrl: String?
    var ingredients: [String]?

    init(dictionary : [String : AnyObject]) {
        self.title = dictionary[Keys.Title] as? String
        self.id = Int(dictionary[Keys.RecipeId] as! String)!
        self.imageUrl = dictionary[Keys.ImageUrl] as? String
        self.ingredients = dictionary[Keys.Ingredients] as? [String]
    }
}

这应该会解析 JSON。


就个人而言,我会删除所有这些!,因为如果有任何问题,它会崩溃。例如:

enum RecipeError: ErrorType {
    case InvalidJSON(message: String, userInfo: [NSObject: AnyObject])
    case MalformedJSON
    case RecipeKeyNotFound
    case BadKeysValues
}

func recipeFromData(data: NSData) throws -> Recipe {
    var jsonObject: AnyObject

    do {
        jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: [])
    } catch let parseError as NSError {
        throw RecipeError.InvalidJSON(message: parseError.localizedDescription, userInfo: parseError.userInfo)
    }

    guard let dictionary = jsonObject as? [String : AnyObject] else {
        throw RecipeError.MalformedJSON
    }

    guard let recipeDictionary = dictionary["recipe"] as? [String: AnyObject] else {
        throw RecipeError.RecipeKeyNotFound
    }

    guard let recipe = Recipe(dictionary: recipeDictionary) else {
        throw RecipeError.BadKeysValues
    }

    return recipe
}

您是否走到这个极端只是您希望能够优雅地捕获什么样的错误的问题,但希望这说明了您希望避免使用强制展开(使用! 或@987654327 @) 如果处理您从远程源获取的数据,这可能会引入您的应用程序必须预料到并优雅地处理而不仅仅是崩溃的问题。

顺便说一句,在上面的例子中,我给了Recipe一个可失败的初始化器:

struct Recipe {
    struct Keys {
        static let Title = "title"
        static let ImageUrl = "image_url"
        static let Ingredients = "ingredients"
        static let RecipeId = "recipe_id"
    }

    let title: String?
    let id: Int
    let imageUrl: String?
    let ingredients: [String]?

    init?(dictionary : [String : AnyObject]) {
        if let idString = dictionary[Keys.RecipeId] as? String, let id = Int(idString) {
            self.id = id
        } else {
            return nil
        }
        self.title = dictionary[Keys.Title] as? String
        self.imageUrl = dictionary[Keys.ImageUrl] as? String
        self.ingredients = dictionary[Keys.Ingredients] as? [String]
    }
}

(注意,我将其设为struct,因为它支持更直观的可失败初始化程序。如果您想要一个类的可失败初始化程序,它要求您在失败之前初始化所有内容(这对我来说似乎违反直觉)。

【讨论】:

    【解决方案2】:

    这是有效的 JSON,可以完美转换为 [String : AnyObject]

    let string = "{\"recipe\":{\"f2f_url\":\"http://food2fork.com/view/20970\",\"image_url\":\"http://static.food2fork.com/98113574b0.jpg\",\"ingredients\":[\"1 (170 gram) can crabmeat\",\"125 grams PHILADELPHIA Light Brick Cream Cheese Spread, softened\",\"2 green onions, thinly sliced\",\"1/4 cup MIRACLE WHIP Calorie-Wise Dressing\",\"12 wonton wrappers\"],\"publisher\":\"All Recipes\",\"publisher_url\":\"http://allrecipes.com\",\"recipe_id\":20970,\"social_rank\":\"41.83825995815504\",\"source_url\":\"http://allrecipes.com/Recipe/Philly-Baked-Crab-Rangoon/Detail.aspx\",\"title\":\"PHILLY Baked Crab Rangoon\"}}"
    
    do{
      let dict = try NSJSONSerialization.JSONObjectWithData(string.dataUsingEncoding(NSUTF8StringEncoding)!, options:NSJSONReadingOptions.AllowFragments) as! [String : AnyObject]
      print(dict)
    } catch let error as NSError{
      print(error.localizedDescription)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-02
      • 2018-06-23
      • 1970-01-01
      • 1970-01-01
      • 2015-06-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多