Swift 解析 JSON 时出现问题:无法将“__NSCFDictionary”类型的值转换为“NSArray”错误
Posted
技术标签:
【中文标题】Swift 解析 JSON 时出现问题:无法将“__NSCFDictionary”类型的值转换为“NSArray”错误【英文标题】:Swift trouble parsing JSON: Could not cast value of type '__NSCFDictionary' to 'NSArray' error 【发布时间】: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 示例
【参考方案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)
【讨论】:
以上是关于Swift 解析 JSON 时出现问题:无法将“__NSCFDictionary”类型的值转换为“NSArray”错误的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 3 中将 JSON 对象解析为 NSArray
解析为对象而不是数组时出现Json错误:JSONObject中的getJSONObject(java.lang.String)无法应用于(int)
使用 Jackson 和消息解析 JSON 文件中的内容时出现问题 - JsonMappingException - 无法反序列化为超出 START_ARRAY 令牌
通过 Ajax 解析 PHP 文件获取的 JSON 数据时出现问题