对编码来说是全新的,所以如果有些东西在这里是非常明显的,请原谅。
我正在开发一个应用程序,我可以用它来跟踪我的举重分裂。我这样写数据:
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)")
})
注意事项:
如果你想确保你按顺序存储你的练习(并按顺序提取数据),那么而不是有练习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 } }
Firebase实时数据库是一个广度第一的搜索和下载。因此,您应该尽可能地使数据库结构扁平化。这意味着观察
exerciseRef.child("Users").child(user.uid).child("splits").child(splitName).child("day (day)")
仍然会下载所有的锻炼天数。