Dispatch.notify 在任务完成之前被调用?
Dispatch.notify being called before task has completed?
我正在尝试从 Firestore 下载数据,将其附加到一个数组,然后在下载所有数据后将其附加到另一个数组。我尝试使用完成处理程序,但它 returns 即使数据尚未全部下载。所以我尝试使用 DispatchGroup 但是 dispatch.notify 在我的任务完成之前被调用。
这是我的代码。我在最后一个 else 括号内调用 dispatch.begin 否则 leave 和 enter 出于某种原因不平衡?
如何等到所有数据都下载完毕,然后在 dispatch.notify 中调用完成?
func SameUniRelatedCourses(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
service.loadUniversityAndCourse { (uni, course) in
let related = RelatedCourses()
let relatedCourseArray = related.getRelatedCourses(userCourse: course)//.prefix(4)
for Course in relatedCourseArray {
let UniRef = Firestore.firestore().collection("User-Courses").document(Course)
UniRef.getDocument { (snapshot, error) in
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"]!)
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if Info.University != uni {
//print("Not in their uni",Info.username!)
}
else if self.sameUniSameCourse.contains(where: { [=11=].uid == Info.uid }) {
//print("already in sameunisamecourse",Info.username!)
}
else {
print("entering")
self.dispatchGroup.enter()
print("1", Info.username!)
self.sameUniRelatedCourses.append(Info)
self.sameUniRelatedCourses.sort { (time1, time2) -> Bool in
return time2.Created!.seconds/1000 > time1.Created!.seconds/1000
}
print("leaving")
self.dispatchGroup.leave()
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
}
}
第二个函数
func sameUniversity(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let UniRef = Firestore.firestore().collection("User-Universities").document(uni)
UniRef.getDocument { (snapshot, error) in
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"])
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if self.sameUniSameCourse.contains(where: { [=12=].uid == Info.uid }) || Info.uid == Auth.auth().currentUser?.uid || self.sameUniRelatedCourses.contains(where: { [=12=].uid == Info.uid }) {
//print("already in master array", Info.username!)
}
else {
print("2", Info.username!)
self.sameUni.append(Info)
self.sameUni.sort { (time1, time2) -> Bool in
return time1.Created!.seconds/1000 > time2.Created!.seconds/1000
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
self.masterArray.append(contentsOf: self.sameUni)
self.spinner.stopAnimating()
self.tableView.reloadData()
completion(true)
}
}
你需要像这样使用Dispatch Group。在执行异步任务之前进入并在完成闭包内调用leave
func SameUniRelatedCourses(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let related = RelatedCourses()
let relatedCourseArray = related.getRelatedCourses(userCourse: course)//.prefix(4)
for Course in relatedCourseArray {
self.dispatchGroup.enter()
let UniRef = Firestore.firestore().collection("User-Courses").document(Course)
UniRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
self.dispatchGroup.enter()
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"]!)
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if Info.University != uni {
//print("Not in their uni",Info.username!)
}
else if self.sameUniSameCourse.contains(where: { [=10=].uid == Info.uid }) {
//print("already in sameunisamecourse",Info.username!)
}
else {
print("entering")
print("1", Info.username!)
self.sameUniRelatedCourses.append(Info)
self.sameUniRelatedCourses.sort { (time1, time2) -> Bool in
return time2.Created!.seconds/1000 > time1.Created!.seconds/1000
}
print("leaving")
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
}
}
第二个函数
func sameUniversity(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let UniRef = Firestore.firestore().collection("User-Universities").document(uni)
self.dispatchGroup.enter()
UniRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
self.dispatchGroup.enter()
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"])
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if self.sameUniSameCourse.contains(where: { [=11=].uid == Info.uid }) || Info.uid == Auth.auth().currentUser?.uid || self.sameUniRelatedCourses.contains(where: { [=11=].uid == Info.uid }) {
//print("already in master array", Info.username!)
}
else {
print("2", Info.username!)
self.sameUni.append(Info)
self.sameUni.sort { (time1, time2) -> Bool in
return time1.Created!.seconds/1000 > time2.Created!.seconds/1000
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
self.masterArray.append(contentsOf: self.sameUni)
self.spinner.stopAnimating()
self.tableView.reloadData()
completion(true)
}
}
A DispatchGroup
添加 enter()
并减去 leave()
调用以确定工作何时完成。在您的情况下,您不会在触发您正在等待的任何异步调用之前进入该组。结果,您正在快速通过您的 enter()s 并且您的小组立即完成。
这里有一个小游乐场来说明这个想法:
import UIKit
import PlaygroundSupport
var str = "Hello, playground"
// Code will race to the notify before any enter() has been called.
func doAsyncWork_racing(completion: @escaping () -> Void) {
let group = DispatchGroup()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
}
group.notify(queue: .main) {
print("\(#function) done!!")
completion()
}
}
// Code will enter() before calling any async work, so the notify does
// not get immediately fired off.
func doAsyncWork_correct(completion: @escaping () -> Void) {
let group = DispatchGroup()
group.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
group.leave()
}
group.notify(queue: .main) {
print("\(#function) done!!")
completion()
}
}
// Same as before, but work is submitted to a different queue and we
// block the thread with wait(), making the whole function blocking.
func doAsyncWork_waiting(completion: @escaping () -> Void) {
let group = DispatchGroup()
let workQueue = DispatchQueue(label: "work")
// Here's an example where the group waits until
// and block the thread its work is done.
group.enter()
workQueue.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
group.leave()
}
group.wait()
print("\(#function) done!!")
completion()
}
doAsyncWork_racing() {
doAsyncWork_correct() {
doAsyncWork_waiting() {
print("all calls done!")
}
}
}
PlaygroundSupport.PlaygroundPage.current.needsIndefiniteExecution = true
我正在尝试从 Firestore 下载数据,将其附加到一个数组,然后在下载所有数据后将其附加到另一个数组。我尝试使用完成处理程序,但它 returns 即使数据尚未全部下载。所以我尝试使用 DispatchGroup 但是 dispatch.notify 在我的任务完成之前被调用。
这是我的代码。我在最后一个 else 括号内调用 dispatch.begin 否则 leave 和 enter 出于某种原因不平衡?
如何等到所有数据都下载完毕,然后在 dispatch.notify 中调用完成?
func SameUniRelatedCourses(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
service.loadUniversityAndCourse { (uni, course) in
let related = RelatedCourses()
let relatedCourseArray = related.getRelatedCourses(userCourse: course)//.prefix(4)
for Course in relatedCourseArray {
let UniRef = Firestore.firestore().collection("User-Courses").document(Course)
UniRef.getDocument { (snapshot, error) in
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"]!)
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if Info.University != uni {
//print("Not in their uni",Info.username!)
}
else if self.sameUniSameCourse.contains(where: { [=11=].uid == Info.uid }) {
//print("already in sameunisamecourse",Info.username!)
}
else {
print("entering")
self.dispatchGroup.enter()
print("1", Info.username!)
self.sameUniRelatedCourses.append(Info)
self.sameUniRelatedCourses.sort { (time1, time2) -> Bool in
return time2.Created!.seconds/1000 > time1.Created!.seconds/1000
}
print("leaving")
self.dispatchGroup.leave()
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
}
}
第二个函数
func sameUniversity(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let UniRef = Firestore.firestore().collection("User-Universities").document(uni)
UniRef.getDocument { (snapshot, error) in
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"])
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if self.sameUniSameCourse.contains(where: { [=12=].uid == Info.uid }) || Info.uid == Auth.auth().currentUser?.uid || self.sameUniRelatedCourses.contains(where: { [=12=].uid == Info.uid }) {
//print("already in master array", Info.username!)
}
else {
print("2", Info.username!)
self.sameUni.append(Info)
self.sameUni.sort { (time1, time2) -> Bool in
return time1.Created!.seconds/1000 > time2.Created!.seconds/1000
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
self.masterArray.append(contentsOf: self.sameUni)
self.spinner.stopAnimating()
self.tableView.reloadData()
completion(true)
}
}
你需要像这样使用Dispatch Group。在执行异步任务之前进入并在完成闭包内调用leave
func SameUniRelatedCourses(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let related = RelatedCourses()
let relatedCourseArray = related.getRelatedCourses(userCourse: course)//.prefix(4)
for Course in relatedCourseArray {
self.dispatchGroup.enter()
let UniRef = Firestore.firestore().collection("User-Courses").document(Course)
UniRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
self.dispatchGroup.enter()
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"]!)
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if Info.University != uni {
//print("Not in their uni",Info.username!)
}
else if self.sameUniSameCourse.contains(where: { [=10=].uid == Info.uid }) {
//print("already in sameunisamecourse",Info.username!)
}
else {
print("entering")
print("1", Info.username!)
self.sameUniRelatedCourses.append(Info)
self.sameUniRelatedCourses.sort { (time1, time2) -> Bool in
return time2.Created!.seconds/1000 > time1.Created!.seconds/1000
}
print("leaving")
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
}
}
第二个函数
func sameUniversity(completion: @escaping (_ success: Bool) -> Void) {
DispatchQueue.main.async {
self.spinner.startAnimating()
}
self.dispatchGroup.enter()
service.loadUniversityAndCourse { (uni, course) in
defer{ self.dispatchGroup.leave() }
let UniRef = Firestore.firestore().collection("User-Universities").document(uni)
self.dispatchGroup.enter()
UniRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error{
print(error.localizedDescription)
}
else {
//append their data to an array
guard let data = snapshot?.data() else {return}
let stringArray = Array(data.keys)
for user in stringArray {
self.dispatchGroup.enter()
let usersRef = Firestore.firestore().collection("users").document(user)
usersRef.getDocument { (snapshot, error) in
defer{ self.dispatchGroup.leave() }
if let error = error {
print(error.localizedDescription)
}
else {
let data = snapshot?.data()
//print("raw data", data?["username"])
if let dictionary = data as [String:AnyObject]? {
let Info = UserInfo(dictionary: dictionary)
if self.sameUniSameCourse.contains(where: { [=11=].uid == Info.uid }) || Info.uid == Auth.auth().currentUser?.uid || self.sameUniRelatedCourses.contains(where: { [=11=].uid == Info.uid }) {
//print("already in master array", Info.username!)
}
else {
print("2", Info.username!)
self.sameUni.append(Info)
self.sameUni.sort { (time1, time2) -> Bool in
return time1.Created!.seconds/1000 > time2.Created!.seconds/1000
}
}
}
}
}
}
}
}
}
self.dispatchGroup.notify(queue: .main) {
print("done")
//call Completoion here
self.masterArray.append(contentsOf: self.sameUni)
self.spinner.stopAnimating()
self.tableView.reloadData()
completion(true)
}
}
A DispatchGroup
添加 enter()
并减去 leave()
调用以确定工作何时完成。在您的情况下,您不会在触发您正在等待的任何异步调用之前进入该组。结果,您正在快速通过您的 enter()s 并且您的小组立即完成。
这里有一个小游乐场来说明这个想法:
import UIKit
import PlaygroundSupport
var str = "Hello, playground"
// Code will race to the notify before any enter() has been called.
func doAsyncWork_racing(completion: @escaping () -> Void) {
let group = DispatchGroup()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
}
group.notify(queue: .main) {
print("\(#function) done!!")
completion()
}
}
// Code will enter() before calling any async work, so the notify does
// not get immediately fired off.
func doAsyncWork_correct(completion: @escaping () -> Void) {
let group = DispatchGroup()
group.enter()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
group.leave()
}
group.notify(queue: .main) {
print("\(#function) done!!")
completion()
}
}
// Same as before, but work is submitted to a different queue and we
// block the thread with wait(), making the whole function blocking.
func doAsyncWork_waiting(completion: @escaping () -> Void) {
let group = DispatchGroup()
let workQueue = DispatchQueue(label: "work")
// Here's an example where the group waits until
// and block the thread its work is done.
group.enter()
workQueue.asyncAfter(deadline: .now() + .seconds(3)) {
for i in 0..<5 {
group.enter()
print("\(#function) doing task \(i)")
group.leave()
}
group.leave()
}
group.wait()
print("\(#function) done!!")
completion()
}
doAsyncWork_racing() {
doAsyncWork_correct() {
doAsyncWork_waiting() {
print("all calls done!")
}
}
}
PlaygroundSupport.PlaygroundPage.current.needsIndefiniteExecution = true