从Firebase RT数据库中提取数据有问题



对编码来说是全新的,所以如果有些东西在这里是非常明显的,请原谅。

我正在开发一个应用程序,我可以用它来跟踪我的举重分裂。我这样写数据:

public func writeNewExercise(splitName: String, day: Int, exerciseNum: Int, exerciseName: String, sets: String, repsSecs: String, isTimed: Bool, completion: @escaping (Bool) -> Void) {

let user = AuthManager.shared.user
var exerciseRef: DatabaseReference!
exerciseRef = Database.database().reference(withPath: "(user.uid)/splits/(splitName)/day (day)/exercise (exerciseNum)")

var dataDictionary: [String: Any] = [:]
dataDictionary["Exercise Name"] = exerciseName
dataDictionary["Sets"] = sets
dataDictionary["Reps or Secs"] = repsSecs
dataDictionary["Is Timed"] = isTimed

exerciseRef.setValue(dataDictionary) { error, _ in
if error == nil {
completion(true)
return
} else {
completion(false)
return
}

}

}

这给了我一个JSON字典在Firebase看起来像这样:

{
"8aIzPgurRLPPEYDpXWv54r5JjvH3" : {
"splits" : {
"Test Split" : {
"day 1" : {
"exercise 0" : {
"Exercise Name" : "Curls",
"Is Timed" : false,
"Reps or Secs" : "12",
"Sets" : "4"
}
}
}
}
},

我现在要做的是拉出这些数据,这样我就可以将每个练习插入到tableView单元格中。不想用它做任何花哨的事情——只是能够查看它,这样我就可以跟踪我的分裂。我这样做更多的是为了练习而不是实用性。我试过用15种不同的方法提取数据,但无论我怎么做,都行不通。我完全被难住了。下面是我现在的代码:

public func downloadPost(splitName: String, day: Int, completion: @escaping (Bool) -> Void){

let user = AuthManager.shared.user
var exerciseRef: DatabaseReference!
exerciseRef = Database.database().reference()

var exerciseArray = [Exercise]()

exerciseRef.child("Users").child(user.uid).child("splits").child(splitName).child("day (day)").observe(.value) { snapshot in

if snapshot.exists(){
for x in 0...100{

let nameValue = snapshot.childSnapshot(forPath: "exercise (x)/Exercise Name").value
let setsValue = snapshot.childSnapshot(forPath: "exercise (x)/Sets").value
let repsOrSecsValue = snapshot.childSnapshot(forPath: "exercise (x)//Sets/Reps or Secs").value
let isTimedValue = snapshot.childSnapshot(forPath: "exercise (x)/Sets/Is Timed").value

let exercise = Exercise(name: "(nameValue!)",
sets: "(setsValue!)",
repsOrSecs: "(repsOrSecsValue!)",
isTimed: isTimedValue as? Bool ?? false)
print(exercise.name)
print(exercise.sets)
print(exercise.repsOrSecs)
print(exercise.isTimed)
exerciseArray.append(exercise)
completion(true)
return
}
} else {
print("no snapshot exists")
}

print(exerciseArray)

}
}

Exercise是我创建的一个自定义类,它有名称、集合数量、重复次数和Bool " istimmed "这段代码输出:

no snapshot exists, []

尝试其他东西,我让它打印如下内容:

空,0,0,假

我试过的其他方法有:

  • 使用斜杠导航而不是在。observe.value
  • 中链接。child
  • 使用。getdata代替。observe
  • 到处抛出DispatchQueue.main.async
  • 使exerciseRef成为整个数据库,然后在分配快照时调用到特定的点。
  • 其他

到目前为止,我可能已经花了大约15个小时来研究这个问题,但我真的想不明白。任何帮助都会非常感激。我会密切关注这篇文章,如果有必要的话,我会把我可能遗漏的信息贴出来。

谢谢!

使用下面Medo提供的代码使一切正常工作。对于其他尝试这样做的人,在像Medo演示的那样拉动数组后,只需将tableViewCell中的所有标签设置为ExportedArray[indexPath.row]. classpropertyyouwant

我的解决方案是:

public func downloadPost(splitName: String, day: Int, completion: @escaping (([Exercise]) -> ())){

let user = AuthManager.shared.user
var exerciseRef: DatabaseReference!
exerciseRef = Database.database().reference()

var exerciseArray = [Exercise]()

exerciseRef.child(user.uid).child("splits").child(splitName).child("day (day)").observe(.value, with: { snapshot in

guard let exercises = snapshot.children.allObjects as? [DataSnapshot] else {
print("Error: No snapshot")
return
}



for exercise in exercises {
let exerciseData = exercise.value as? [String:Any]

let exerciseName = exerciseData["Exercise Name"] as? String
let isTimed = exerciseData["Is Timed"] as? Bool
let repsOrSecs = exerciseData["Reps or Secs"] as? String
let sets = exerciseData["Sets"] as? String

let exerciseIndex = Exercise(name: "(exerciseName)",
sets: "(sets)",
repsOrSecs: "(repsOrSecs)",
isTimed: isTimed)

exerciseArray.append(exerciseIndex)

}
completion(exerciseArray)  
}
}

您可以调用函数downloadPost并从中提取数组,如下所示:

downloadPost(splitName: "", day: 0, completion: {
aNewArray in

// aNewArray is your extracted array [Exercise]
print("(aNewArray)")

})

注意事项:

  1. 如果你想确保你按顺序存储你的练习(并按顺序提取数据),那么而不是有练习0,1,2…(在你的数据库中),用一个名为"childbyautoid"的id来命名它。当您添加/推送或提取数据时,Firebase将自动为您排序。将writeNewExercise函数替换为:

    let user = AuthManager.shared.user
    var exerciseRef: DatabaseReference!
    let key = Database.database().reference().childByAutoId().key ?? ""
    exerciseRef = Database.database().reference(withPath: "(user.uid)/splits/(splitName)/day (day)/(key)")
    var dataDictionary: [String: Any] = [:]
    dataDictionary["Exercise Name"] = exerciseName
    dataDictionary["Sets"] = sets
    dataDictionary["Reps or Secs"] = repsSecs
    dataDictionary["Is Timed"] = isTimed
    exerciseRef.setValue(dataDictionary) { error, _ in
    if error == nil {
    completion(true)
    return
    } else {
    completion(false)
    return
    }
    }
    
  2. Firebase实时数据库是一个广度第一的搜索和下载。因此,您应该尽可能地使数据库结构扁平化。这意味着观察exerciseRef.child("Users").child(user.uid).child("splits").child(splitName).child("day (day)")仍然会下载所有的锻炼天数。

最新更新