我对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
}
感谢。
答案 0 :(得分: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
}
你是否走到这个极端只是一个问题,你希望能够优雅地捕获什么样的错误,但希望这说明了你要避免使用强制解包(使用!
或as!
)如果处理您从远程来源获取的数据,这可能会引入您的应用必须预期和优雅处理的问题,而不仅仅是崩溃。
顺便说一句,在上面的例子中,我给了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
,因为它支持更直观的可用初始化器。如果你想为一个类提供一个可用的初始化器,它需要你在失败之前初始化所有东西(看起来似乎反对我直截了当。)
答案 1 :(得分:0)
这是有效的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)
}