首页 > 解决方案 > 从 Firebase Swift 解析数据 JSON

问题描述

我尝试解析和分配来自 Firebase 的数据 Firebase 中的结构如下所示:

在此处输入图像描述

我尝试从数据库中获取数据并将其分配给类的实例Meal

ref = Database.database().reference()
        databaseHandle = ref.child("Meal").observe(.value, with: { (snapshot) in
            var downloadedName : String!
            var downloadedPhoto : String!
            var downloadedRating : Int!
            var downloadedSteps : Array <String>!
            var downloadedIngredients : [Dictionary <String, String>]!

            print(snapshot.value)
            if let dict = snapshot.value as? Dictionary<String, Any>{
                print("VALUES!!!")


                for key in dict.keys {

                    if let values = dict[key] as? Dictionary<String, Any> {
                        print(values)

                        if let name = values["name"] as? String{
                            downloadedName = name
                        }

                        if let photo = values["photo"] as? String{
                            downloadedPhoto = photo
                        }

                        if let rating = values["rating"] as? Int{
                            downloadedRating = rating
                        }
                        if let steps = values["steps"] as? Array<String>{
                            downloadedSteps = steps
                        }
                        if let ingredients = values["ingredients"] as? [Dictionary <String, String>]{
                            downloadedIngredients = ingredients
                        }

                         let meal = Meal(name: downloadedName, photo: UIImage(named: downloadedPhoto), rating: downloadedRating, steps: downloadedSteps, ingredients: downloadedIngredients)           
                        self.meals.append(meal!);
                    }
                }

Meal 类本身如下所示:

class Meal {
    var name: String
    var photo: UIImage?
    var rating: Int
    var steps: Array<String>
    var ingredients: [Dictionary<String, String>]}

我得到第一个print- 整个数据,所以与 DB 的连接没问题,但是当我尝试分配它时 - 没有任何反应,没有错误,没有数据(第二个print消息VALUES!!!根本没有显示,我做错了什么?

这也是我首先得到的print

Optional(<__NSArrayM 0x600002fdaa60>(
{
    ingredients =     (
                {
            amount = 100;
            ingredient = milk;
            measurement = ml;
        },
                {
            amount = 120;
            ingredient = milk;
            measurement = ml;
        }
    );
    name = "Caprese Salad";
    photo = meal1;
    rating = 4;
    steps =     (
        test1,
        test11
    );
},
{
    ingredients =     (
                {
            amount = 100;
            ingredient = milk;
            measurement = ml;
        },
                {
            amount = 120;
            ingredient = milk;
            measurement = ml;
        }
    );
    name = "Chicken and Potatoes";
    photo = meal2;
    rating = 3;
    steps =     (
        test2,
        test22
    );
},
{
    ingredients =     (
                {
            amount = 100;
            ingredient = milk;
            measurement = ml;
        },
                {
            amount = 120;
            ingredient = milk;
            measurement = ml;
        }
    );
    name = "Pasta with Meatballs";
    photo = meal3;
    rating = 2;
    steps =     (
        test3,
        test33
    );
}
)
)

所以,我假设,我在某些时候以错误的方式检索数据,我该如何修复它?

标签: iosjsonswiftfirebasefirebase-realtime-database

解决方案


你有:

print(snapshot.value)
if let dict = snapshot.value as? Dictionary<String, Any>{
    print("VALUES!!!")
    ....
}

你说print(snapshot.value)那叫不叫print("VALUES!!!")。好吧,这意味着snapshot.value或者不是Dictionary哪个键是String对象,值是类型Any

现在,让我们看看输出snapshot.value

Optional(<__NSArrayM 0x600002fdaa60> ...

NSArrayM=> NSMutableArray,所以snapshot.value是 a Array,而不是 a Dictionary。当然as? Dictionary会失败!

所以你需要把它当作一个Array.

速写:

if let array = snapshot.value as? [[String: Any]] {
    for aValue in array {
        let name = aValue["name"] as? String ?? "unnamed"
        let photoName = aValue["photo"] as? String ?? "noPhoto"
        let rating = aValue["rating"] as? Int ?? 0
        let steps = aValue["steps"] as? [String] ?? []
        let ingredients = aValue["ingredients"] as? [[String: String]] ?? [:]
        let meal = Meal(name: name, photo: UIImage(named: photoName), rating: rating, steps: steps, ingredients: ingredients)           
        self.meals.append(meal)
    }
}

您的方法也可能有什么问题:

var downloadedName : String!
loop {
    if let name = values["name"] as? String {
        downloadedName = name
    }
    let meal = Meal(name: downloadedName, ...)
}

好吧,如果第二个值没有名称(因为它不是 aString或因为该值不存在),那么您downloadedName将拥有第一个的值,但其余的值为第二个.

我使用的方法:

let name = aValue["name"] as? String ?? "unnamed"

意思是,如果它是零,它会得到一个默认值。但是你可以决定只接受一个有效的,通过 aguard letif let可能在所有子值上。

例如:

if let name = aValue["name"] as? String,
   let let photoName = aValue["photo"] as? String, 
   ... {
    let meal = Meal(name: name, photo: UIImage(named: photoName)
    self.meals.append(meal)
}

而且由于您Meal.init()似乎返回了一个可选项,因此您也可以将其添加到if let并避免meal.


推荐阅读