我正在为库创建一个应用程序。我正在尝试从Firebase中获取用户已检出的所有图书,但我尝试使用DispatchGroup使该函数异步似乎并不起作用。我怀疑这是因为在函数内部找到了for-in循环。
# supposing x contains variables A, B, C, etc.
interacting_variables <- c('B', 'D', 'E', 'F')
my_glm.hex <- h2o.glm(y=y_idx,x=x_idx,
training_frame = "my_train",
validation_frame = "my_valid",
model_id = "my_glm.hex",
family = "binomial",
lambda_search = TRUE,
balance_classes = TRUE,
interactions = interacting_variables)
以下是print()语句的输出:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.coderz.creative.music.Fragment.HomeFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/chart_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="10dp">
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/pie_chart_spend"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.github.mikephil.charting.charts.PieChart>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="10dp">
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/bar_chart_spend"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.github.mikephil.charting.charts.BarChart>
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="10dp">
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/pie_chart_spend_on_click"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.github.mikephil.charting.charts.BarChart>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</FrameLayout>
输出的前两行应在其他所有内容打印后打印。我真的需要一些帮助,我已经坚持了几个小时。谢谢!
编辑: 根据要求,这是我的Firebase结构:
func fetchHistory() {
if items.count > 0 {
items.removeAll()
}
let myGroup = DispatchGroup()
myGroup.enter()
var itemNames = [String]() // this holds the names of the child values of /users/uid/items/ <-- located in Firebase Database
guard let uid = fAuth.currentUser?.uid else {return}
fData.child("users").child(uid).child("items").observe(.value, with: { snapshot in
// make sure there is at least ONE item in the history
if snapshot.childrenCount > 0 {
let values = snapshot.value as! NSDictionary
for i in values.allKeys {
itemNames.append(i as! String)
}
print(itemNames)
let uid = fAuth.currentUser!.uid // get the UID of the user
for item in itemNames {
fData.child("users").child(uid).child("items").child(item).observe(.value, with: { snapshot in
let values = snapshot.value as! NSDictionary
let bookTitle = values["title"] as! String
print(bookTitle)
let bookAuthor = values["author"] as! String
print(bookAuthor)
let bookCoverUrl = values["coverUrl"] as! String
print(bookCoverUrl)
let bookStatus = values["status"] as! String
print(bookStatus)
let bookDueDate = values["dueDate"] as! String
print(bookDueDate)
let book = Book(name: bookTitle, author: bookAuthor, coverUrl: bookCoverUrl, status: bookStatus, dueDate: bookDueDate)
self.items.append(book)
})
}
self.booksTable.isHidden = false
} else {
self.booksTable.isHidden = true
}
})
myGroup.leave()
myGroup.notify(queue: DispatchQueue.main, execute: {
self.booksTable.reloadData()
print("Reloading table")
})
}
答案 0 :(得分:2)
有几个问题:
模式是leave
必须在异步调用的完成处理程序中调用 。您希望这是在闭包内执行的最后一件事,因此您可以将其添加为完成处理程序闭包中的最后一行。
或者我更喜欢使用defer
子句,这样你不仅知道它将是闭包中执行的最后一件事,而且还是:
leave
;和enter
和leave
调用在视觉中直接显示在代码中,使您无需在闭包底部进行视觉搜索,以确保正确调用它。如果你想等待for
循环中的异步调用,你也必须在那里添加它。
非常小的一点,但在成功解开uid
之前,您可能不想创建该组。如果可能DispatchGroup
而不执行任何异步代码,为什么要创建return
?
因此,或许:
func fetchHistory() {
if items.count > 0 {
items.removeAll()
}
var itemNames = [String]()
guard let uid = fAuth.currentUser?.uid else {return}
let group = DispatchGroup()
group.enter()
fData.child("users").child(uid).child("items").observe(.value, with: { snapshot in
defer { group.leave() } // in case you add any early exits, this will safely capture
if snapshot.childrenCount > 0 {
...
for item in itemNames {
group.enter() // also enter before we do this secondary async call
fData.child("users").child(uid).child("items").child(item).observe(.value, with: { snapshot in
defer { group.leave() } // and, again, defer the `leave`
...
})
}
...
} else {
...
}
})
group.notify(queue: .main) {
self.booksTable.reloadData()
print("Reloading table")
}
}
答案 1 :(得分:0)
虽然Rob有一个很好的答案,但我会从不同的方向寻求解决方案。
一本书只能让一个人检查出来(一次),但借款人可以拥有多本书。由于这种关系,只需将拥有该书的人与书本身结合起来:
这是一个建议的用户结构
users
uid_0
name: "Rob"
uid_1
name: "Bill"
然后是书籍节点
books
78DFB90A-DE5B-47DE-ADCA-2DAB9D43B9C8
author: "Suzanne Collins"
coverUrl: "https://images.gr assets.com/books/1358275419s/..."
dueDate: "Date"
status: "Checked"
title: "Mockingjay (The Hunger Games, #3)"
checked_out_by: "uid_0"
check_date: "20180118"
然后获取Rob已检出的所有书籍并使用这些结果填充数组并将其显示在tableview中变得非常简单:
//var bookArray = [Book]() //defined as a class var
let booksRef = self.ref.child("books")
let query = booksRef.queryOrdered(byChild: "checked_out_by").queryEqual(toValue: "uid_0")
booksRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let book = Book(initWithSnap: snap) //take the fields from the snapshot and populate the book
self.bookArray.append(book)
}
self.tableView.reloadData()
})
然后你问自己,&#34;自我,如果我想要一本谁签出这本书的记录怎么办?&#34;
如果您需要该功能,只需稍微更改books节点,以便我们可以利用深层查询;
books
78DFB90A-DE5B-47DE-ADCA-2DAB9D43B9C8
author: "Suzanne Collins"
coverUrl: "https://images.gr assets.com/books/1358275419s/..."
dueDate: "Date"
status: "Checked"
title: "Mockingjay (The Hunger Games, #3)"
check_out_history
"uid_0" : true
"uid_1" : true
并将签出日期移至用户节点。然后,您可以查询任何图书的任何用户,并查看谁签出该图书的历史记录。 (需要有逻辑来确定当前谁有这本书所以这只是一个起点)
或者,如果您想要其他选项,请保留一个单独的图书历史记录节点
book_history
78DFB90A-DE5B-47DE-ADCA-2DAB9D43B9C8
-9j9jasd9jasjd4 //key is created with childByAutoId
uid: "uid_0"
check_out_date: "20180118"
check_in_date: "20180122"
condition: "excellent"
-Yuhuasijdijiji //key is created with childByAutoId
uid: "uid_1"
check_out_date: "20180123"
check_in_date: "20180125"
condition: "good"
这个概念是让Firebase为您完成工作,而不是反复迭代数组,并且必须发出数十个调用来获取您需要的数据。调整结构使得将来维护和扩展变得更加简单 - 它避免了异步代码的所有问题,因为它都在闭包内;干净整洁。