我的函数 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 图像数组。
一般模式是:
- 使用
@escaping
完成处理程序闭包。
- 使用调度组跟踪所有异步请求。
- 在单个请求完成时将结果存储在字典中。我们对结果使用字典,因为对于并发请求,您不知道请求将按什么顺序完成,因此我们会将其存储在一个结构中,以便我们稍后可以从中高效地检索结果。
- 使用 dispatch group
notify
闭包,指定所有请求完成后应该发生什么。在这种情况下,我们将从未排序的字典中构建一个已排序的图像数组,并调用完成处理程序闭包。
- 顺便说一句,应该避免使用强制解包运算符(
!
或 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
个实例
嗨,我正在编写一个函数来从 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 图像数组。
一般模式是:
- 使用
@escaping
完成处理程序闭包。 - 使用调度组跟踪所有异步请求。
- 在单个请求完成时将结果存储在字典中。我们对结果使用字典,因为对于并发请求,您不知道请求将按什么顺序完成,因此我们会将其存储在一个结构中,以便我们稍后可以从中高效地检索结果。
- 使用 dispatch group
notify
闭包,指定所有请求完成后应该发生什么。在这种情况下,我们将从未排序的字典中构建一个已排序的图像数组,并调用完成处理程序闭包。 - 顺便说一句,应该避免使用强制解包运算符(
!
或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
个实例