在结构中从FirebaseStorage获取数据

时间:2020-05-04 13:46:56

标签: swift struct firebase-storage

这是我的挑战:我有一个结构。这是使用FirebaseDatabase中的documentSnapshot初始化的。 Struct返回一个数组,然后将其填充到“集合视图”中

这很好,直到我试图将两个图像添加到数组中为止。它们存储在Firebase存储中。初始化时,引用键将传递到结构中(它们在这里,我测试过)。但是,创建myArray时,图像不存在。没有错误信息。 struct / array的所有其他部分都可以正常工作(距离计算等)

感谢任何人的帮助

struct myStruct {

    var myArray = [Any]()

    init?(Name: String, Amount: String, Description: String, SecondName: String, RID: String, GeoPoint: GeoPoint, DID: String) {

        var location = CLLocation()
        var myArray = [Any]()
        var distance: Double
        var imageA = UIImage()
        var imageB = UIImage()

        let refA = Storage.storage().reference().child("Images").child(todayDate).child(DID)
        refA.getData(maxSize: 1000 * 1240 * 1240) { data, error in
            if let error = error {
                print(error.localizedDescription)
            } else {
                imageA = UIImage(data: data!)!
            }
        }

        let refB = Storage.storage().reference().child("Icons").child(RID)
        refB.getData(maxSize: 1000 * 1240 * 1240) { data, error in
            if let error = error { print(error.localizedDescription)
                imageB = (UIImage(named: "DefaultIcon.png") as UIImage?)!
            } else {
                imageB = UIImage(data: data!)!
            }
        }

        location = CLLocation(latitude: GeoPoint.latitude, longitude: GeoPoint.longitude)
        distance = round(location.distance(from: userLocation)/10)*10


        myArray = [Name, Amount, Description, SecondName, String(Int(distance)), GeoPoint, imageA, imageB]

        self.menuItem = menuItem
    }
}

1 个答案:

答案 0 :(得分:0)

看起来,您的结构要完全实例化,需要先等待两个异步数据任务才能完成(获取图像)。由于您启动了它们,但不必等待它们完成,因此在您将数据写入阵列时,图像数据根本不可用。

有很多可能的方法可以解决这种时间依赖性。哪个是最适合您的项目的选择,很大程度上取决于您的用例和体系结构的整体选择。

但是,一般而言,将此类异步数据任务保留在结构的init中是一个好主意,而是在负责创建和管理您的结构的任何类中执行它们。然后将获取的图像作为init参数传递给struct。

这是您的处理方式,以稍微抽象的方式进行了演示:

您当前可能在代码中的某个位置带有一个对象,该对象具有创建和存储类似于以下内容的MyStruct的功能:

func loadMyStruct() {
    self.myStruct = MyStruct(...)
}

该结构创建函数的更好替代方法是:

func loadMyStruct(completion: @escaping ()->Void) {
        DispatchQueue(label: "MyStructDataFetch", attributes: .concurrent).async { [weak self] in // don't block main thread waiting for data tasks to finish
            let dispatchGroup = DispatchGroup() // since we're waiting on two parallel async tasks, we can use a DispatchGroup to group them together

            var imageA: UIImage?
            var imageB: UIImage?

            dispatchGroup.enter() // enter DispatchGroup
            let refA = Storage.storage().reference().child("Images").child(todayDate).child(DID)
            refA.getData(maxSize: 1000 * 1240 * 1240) { data, error in // start 1st data task

                if let error = error {
                    ...
                } else {
                    imageA = UIImage(data: data!)!
                }

                dispatchGroup.leave() // 1st task is done; leave DispatchGroup
            }

            dispatchGroup.enter() // enter DispatchGroup
            let refB = Storage.storage().reference().child("Icons").child(RID)
            refB.getData(maxSize: 1000 * 1240 * 1240) { data, error in // start 2nd data task

                if let error = error {
                    ...
                } else {
                    imageB = UIImage(data: data!)!
                }
                dispatchGroup.leave() // 2nd task is done; leave DispatchGroup
            }

            let _ = dispatchGroup.wait(timeout: DispatchTime.distantFuture) // wait for all tasks to be done, then...

            self?.myStruct = MyStruct(imageA: imageA, imageB: imageB, ...) // ... pass the finished images to MyStruct constructor
            completion() // Optional: notify observer (e.g. UI) that "MyStruct" is now ready to use
        }
    }

相应地调整了结构的初始化:

init?(imageA: UIImage?, imageB: UIImage?, ...) {
 ...