我具有从firebase下载数据的功能:
func downloadData(path: String) -> Data? {
let data: Data?
let storage = Storage.storage()
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
if let error = error {
print("\(error)")
} else {
data = result
print("finished")
}
return data // <-- this is called before closue ends
}
但它不会从存储闭包中返回值。我尝试使用调度组
func downloadData(path: String) -> Data? {
...
let group = DispatchGroup()
group.enter()
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
...
...
group.leave()
}
group.notify(queue: .main) {
return data // <-- build time error! the function doesn't return a value
}
}
所以我尝试了另一种方法:代替了我使用的group.notify():
group.wait()
但是它也不起作用。整个应用程序被冻结,没有任何反应
我尝试了另一个:
let semaphore = DispatchSemaphore(value: 0)
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
...
...
semaphore.signal()
}
semaphore.wait()
return data // <-- nothing happens... it is not being executed
关于如何解决这个问题的任何想法?
UPDATE
我尝试使用完成选项,但它仍然没有等待下载。
这是我的externalFunction:
var soundData: Data?
var imageData: Data?
downloadData(path: soundPath) { sound in
soundData = sound
downloadData(path: imageData) { image in
imageData = image
}
}
doMoreStuff() // <-- called before completeion blocks executed
使用完成而不是返回->
func downloadData(path: String, _ completion: @escaping (Data?) -> Void) {
let data: Data?
let storage = Storage.storage()
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
if let error = error {
print("\(error)")
} else {
data = result
print("finished")
}
completion(data)
}
}
downloadData(path:,_)
的用法
downloadData(path: "") { data in
// Your data is in here
print("Data is:", data)
}
[如果没有某种类型的完成闭包,您将无法真正做到这一点,因为您将阻塞调用该函数的线程,可能是UI线程。
另一种选择是使用苹果公司新的Combine框架并返回Future
import Combine
func downloadData(path: String) -> Future<Data, Error> {
return Future<Data, Error> { promise in
let storage = Storage.storage()
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
if let error = error {
promise(.failure(error))
} else {
promise(.success(result))
}
}
}
}
var bag = Set<AnyCancellable>()
downloadData(path: "test")
.subscribe(on: DispatchQueue.main)
.sink(receiveCompletion: { (res) in
<#code#>
}) { (data) in
<#code#>
}
.store(in: &bag)
您应该对数据使用完成块,而不是返回数据,方法如下:
func downloadData(path: String, completion: @escaping ((Data?) -> Void)?) {
...
let group = DispatchGroup()
group.enter()
storage.reference(forURL: path).getData(maxSize: 1024 * 1024) { (result, error) in
...
...
group.leave()
}
group.notify(queue: .main) {
completion?(data)
}
}