这是显示异步数据的好方法吗? [英] Is this a good way to display asynchronous data?

查看:64
本文介绍了这是显示异步数据的好方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是异步编码的新手,我想知道我用来快速获取和显示数据的方法是否被认为是正确的.

I'm new to asynchronous coding and am wondering if the method I'm using to fetch and display data is considered correct in swift.

此方法从数据库的用户部分获取对象的列表,然后为列表中的每个项目获取图片.我要告知是否已获取所有图像的方法是在它们到达时将它们推到数组中,然后如果该数组的长度等于我重新加载视图的对象列表.这是我的代码:

This method gets a list of objects from a user's section in the database, then fetches a picture for each item in the list. The way I'm telling if all images have been fetched is pushing them to an array as they arrive, then if that array's length is equal to the list of objects I reload the view. Here is my code:

var pets = [String]()
var imgs = [UIImage]()

override func viewDidAppear(_ animated: Bool) {
        imgsLoaded = 0
        imgs.removeAll(keepingCapacity: false)  // Clear images array
        pets.removeAll(keepingCapacity: false)  // Clear list of objects

        let userRef = FIRDatabase.database().reference().child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("pets")

        userRef.observeSingleEvent(of: .value, with: { snapshot in  // fetch list of objects from database
            if (snapshot.value as? Bool) != nil {                   // User has no pets added
                self.loadScrollView()                               // Reload view
            } else if let snap = snapshot.value as? NSDictionary {  // User has pets
                for value in snap {
                    self.pets.append(value.key as! String)          // Append object to list of objects
                }
                for i in 0..<self.pets.count {                      // For each item in the list, fetch its corresponding image
                    let imgRef = FIRStorage.storage().reference().child("profile_images").child(self.pets[i]+".png")
                    imgRef.data(withMaxSize: 15 * 1024 * 1024) { (data, error) -> Void in
                        if error != nil {
                            print(error)
                        }

                        // Create a UIImage, add it to the array
                        self.imgs.append(UIImage(data: data!)!)      // Push image to list of images
                        self.imgsLoaded+=1
                        if self.imgsLoaded == self.pets.count {      // If same number of images loaded, reload the view
                            self.loadScrollView()
                        }
                    }
                }
            }
        })
    }

正如我所说,我是异步编码的新手,并且想听听做我正在尝试的正确方法.我的方法的一个问题是,图像数组可能与数据数组不对齐,因为可能会无序获取图像.我很想学习执行此操作的最佳方法,所以请让我知道!

As I said, I'm new to asynchronous coding and would like to hear what the proper way of doing what I'm attempting. One problem with my method is the images array might not align with the data array since an image can be fetched out of order. I'd love to learn the best way to do this so let me know please!

确保我的数据与相应图像对齐的一种方法是设置一个字典,其中键是数据,值是我猜到的图像.

A way to make sure my data lines up with the corresponding images is to set a dictionary of sorts with the key being the data and the value being the image I guess.

推荐答案

我建议使用DispatchGroup而不是将2个数组中的项目数保持计数.这还可以跟踪跨多个线程的进度,每个块在组中的enter()leave()中注册.然后,一旦所有块都进入并离开了notify块,就会调用它来刷新UI.如果其中一个图像的加载失败,还可以使用带有占位符图像的字典.总比忽略失败案例好.

I would suggest using a DispatchGroup rather than keeping count of the number of items in 2 arrays. This would also allow to keep track of the progress across multiple threads with each block registered with enter() and leave() on the group. Then once all blocks have entered and left the notify block is called which could refresh your UI. Also using a dictionary with a place holder image in case the loading of one of the images fails. would be better than ignoring the failure case.

由于没有跟踪2个数组的数量,因此这也可能更易于阅读和推理.使用enter()leave()

This may also be easier to read and reason since there is no tracking the count of 2 arrays. The intention is clearer with enter() and leave()

var imgs = [String: UIImage]()
var dispatchGroup = DispatchGroup()

 override func viewDidAppear(_ animated: Bool) {

    let userRef = FIRDatabase.database().reference().child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("pets")

    userRef.observeSingleEvent(of: .value, with: { [weak self] snapshot in  // fetch list of objects from database
        if (snapshot.value as? Bool) != nil {                   // User has no pets added
            self?.loadScrollView()                               // Reload view
        } else if let snap = snapshot.value as? NSDictionary {  // User has pets
            for value in snap {
                self?.dispatchGroup.enter()
                let imgRef = FIRStorage.storage().reference().child("profile_images").child(self!.pets[i]+".png")
                imgRef.data(withMaxSize: 15 * 1024 * 1024) { (data, error) -> Void in
                    if let error = error {
                        print(error) // handle the error here but still call .leave() on the group to be sure the notify block is called.
                        imgs[value] = somePlaceHolderImage
                        self?.dispatchGroup.leave()
                    } else if let data = data, let image = UIImage(data: data) {
                        imgs[value] = image
                        self?.dispatchGroup.leave()
                    }

                    dispatchGroup.notify(queue: DispatchQueue.main, execute: {
                        self?.loadScrollView()
                    })
                }
            }
        }
    })
}

这篇关于这是显示异步数据的好方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆