从Firebase存储闭包Swift中获取值后,在函数内部返回值

问题描述 投票:0回答:3

我具有从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
swift firebase
3个回答
0
投票

使用完成而不是返回->

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)
}

0
投票

[如果没有某种类型的完成闭包,您将无法真正做到这一点,因为您将阻塞调用该函数的线程,可能是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)

0
投票

您应该对数据使用完成块,而不是返回数据,方法如下:

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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.