我的函数 returns 空数组 swift 并解析

My function returns empty array in swift and parse

嗨,我正在编写一个函数来从 swift 中的解析服务器获取数据,一切正常,数据读取良好。但是当我尝试 return 数组时,它 return 给我一个空数组。 我还在“后台获取数据”中添加了一个打印,数组正在获取 full.So 问题是没有获取数据。

public func getthearray() -> Array<UIImage>
{
    let user = PFUser.current()
    let array = user?["Photos"] as! Array<PFFileObject>
    var imagearray = [UIImage]()

    for x in array
    {
        x.getDataInBackground
        { (dataa, error) in

            var img = UIImage(data: dataa!)
            imagearray.append(img!)
        }
    }

    return imagearray
}

函数 return 是一个空数组的原因是 x.getDataInBackground 完成中的代码被异步调用,并且在任何图像被添加到数组之前,派系将已经 return.

这是解决方案(有 2 个版本),您的函数用完成处理程序和 Grand Central Dispatch 稍微重构和重写

方法 1. 信号量

public func getTheArray(_ completion: @escaping ([UIImage]) -> Void) {
    let user: PFUser = .current()
    let array = user?["Photos"] as? [PFFileObject] ?? []
    var result = [UIImage]()

    let semaphore = DispatchSemaphore(value: 0)
    // dispatch to a separate thread which we can safely occupy and block
    // while waiting for the results from async calls.
    DispatchQueue.global().async {
        for file in array {
            file.getDataInBackground { (data, error) in
                if let data = data, let image = UIImage(data: data) {
                    result.append(image)
                }
                // the result have arrived, signal that we are ready
                // to move on to another x
                semaphore.signal()
            }

            // wait until the `signal()` is called, thread is blocked
            semaphore.wait()
        }
        // dispatch to main queue where we are allowed to perform UI updates
        DispatchQueue.main.async {
            // call the completion, but we are doing it only once,
            // when the function is finished with its work
            completion(result)
        }
    }
}

方法 2. 调度组

public func getTheArray(_ completion: @escaping ([UIImage]) -> Void) {
    let user: PFUser = .current()
    let array = user?["Photos"] as? [PFFileObject] ?? []
    var result = [UIImage]()

    let group = DispatchGroup()
    for file in array {
        group.enter()
        file.getDataInBackground { (data, error) in
            if let data = data, let image = UIImage(data: data) {
                result.append(image)
            }
            group.leave()
        }
    }

    // notify once all task finish with `leave()` call.
    group.notify(queue: .main) {
        // call the completion, but we are doing it only once,
        // when the function is finished with its work
        completion(result)
    }
}

用法

你会这样称呼它

getTheArray { result in
    // do what you want with result which is your array of UIImages
}

文档:

相关博文:

您应该使用其他人讨论的完成处理程序闭包,以便在完成所有请求后异步 return 图像数组。

一般模式是:

  1. 使用 @escaping 完成处理程序闭包。
  2. 使用调度组跟踪所有异步请求。
  3. 在单个请求完成时将结果存储在字典中。我们对结果使用字典,因为对于并发请求,您不知道请求将按什么顺序完成,因此我们会将其存储在一个结构中,以便我们稍后可以从中高效地检索结果。
  4. 使用 dispatch group notify 闭包,指定所有请求完成后应该发生什么。在这种情况下,我们将从未排序的字典中构建一个已排序的图像数组,并调用完成处理程序闭包。
  5. 顺便说一句,应该避免使用强制解包运算符(!as!),尤其是在处理网络请求时,其成功或失败不在您的控制范围内。我们通常会使用 guard 语句来测试可选值是否已安全解包。

因此:

func fetchImages(completion: @escaping ([UIImage]) -> Void) {
    guard
        let user = PFUser.current(),
        let files = user["Photos"] as? [PFFileObject]
    else {
        completion([])
        return
    }

    var images: [Int: UIImage] = [:]                         // dictionary is an order-independent structure for storing the results
    let group = DispatchGroup()                              // dispatch group to keep track of asynchronous requests

    for (index, file) in files.enumerated() {
        group.enter()                                        // enter the group before asynchronous call
        file.getDataInBackground { data, error in
            defer { group.leave() }                          // leave the group when this completion handler finishes

            guard
                let data = data,
                let image = UIImage(data: data)
            else {
                return
            }

            images[index] = image
        }
    }

    // when all the asynchronous tasks are done, this `notify` closure will be called

    group.notify(queue: .main) {
        let array = files.indices.compactMap { images[[=10=]] } // now rebuild the ordered array
        completion(array)
    }
}

而且,您可以像这样使用它:

fetchImages { images in
    // use `images` here, e.g. if updating a model object and refreshing the UI, perhaps:

    self.images = images
    self.tableView.reloadData()
}

// but not here, because the above runs asynchronously (i.e. later)

但是考虑到我们正在调用异步 API,我们的想法是采用异步模式,并使用调度组来跟踪它们何时全部完成。但是通常不鼓励使用调度信号量,因为它们强制请求按顺序执行,一个接一个,这会减慢它的速度(例如,根据我的经验,速度会慢两到五倍)。


顺便说一句,我们通常希望报告成功或失败。因此,我们将闭包的参数设置为 Result<[UIImage], Error>(如果你想要单个 Error)或 [Result<UIImage, Error>](如果你想要 UIImage,而不是 [UIImage] ] 或 Error 每个文件。但是这里还不足以知道你想要什么样的错误处理。但仅供参考。


虽然我已经回答了上面的战术问题,但我们真的应该问一下您可能要处理多少张图片。如果您正在检索大量图像 and/or 用户的连接速度较慢,则不鼓励使用这种模式(称为“急切”获取图像)。首先,如果它们很多,它可能会很慢。其次,图像会占用大量内存,如果您在任何给定时间点只需要它们的一个子集,您可能不想加载所有图像。我们经常会重构我们的应用程序以采用“惰性”获取图像,根据需要检索它们,而不是全部预先检索。或者,如果您想进行急切获取,请将资产作为文件下载到缓存文件夹(减少 RAM 消耗)并在需要时在 UI.

中创建 UIImage 个实例