等待Parse Async函数在Swift中完成

时间:2016-02-11 00:57:03

标签: swift uitableview asynchronous parse-platform

我正在等待 Swift 中的 Parse 异步函数重新加载 UITableView

我不确定Completion Handler在这种情况下是否有用。或派遣异步。

我真的很困惑!有人可以帮忙解决这个问题吗?

var posts = [PFObject]()
for post in posts {
    post.fetchInBackground()
}
tableView.reloadData() // I want to execute that when the async functions have finished execution

5 个答案:

答案 0 :(得分:2)

你想使用fetchAllInBackground:块I在循环中启动一堆解析调用时会出现问题,这将导致返回所有这些调用所需的时间超过预期。 fetch documentation

看起来应该是这样的:

PFObject.fetchAllInBackground(posts, block: { (complete, error) in
    if (error == nil && complete) {
        self.tableView.reloadData()
    }
})

需要注意的一点是,在您的示例中,帖子是空的,而且是一个通用的PFObject。我假设这仅仅是为了这个例子。否则,如果你想获得Parse中的所有帖子(而不是更新当前的帖子),你将需要使用PFQuery而不是获取。 query documentation

答案 1 :(得分:1)

您需要使用fetchInBackgroundWithBlock。或者,如果您想等到所有已加载然后更新UI,请使用PFObject的+fetchAllInBackground:block:。请注意,这是一个类方法,因此将被称为PFObject.fetchAllInBackground(...。请参阅文档here

无论哪种方式,因为您在后台线程中运行,您必须更新主线程上的UI。这通常使用dispatch_async完成。

另外需要注意的是,如果在循环中运行fetchInBackgroundWithBlock并在数组中收集所有结果,则数组不是线程安全的。您将不得不使用dispatch_barrier或您自己的同步队列来同步对阵列的访问。第二个选项的代码如下:

// Declared once and shared by each call (set your own name)...
let queue = dispatch_queue_create("my.own.queue", nil)

// For each call...
dispatch_sync(queue) {
    self.myArray.append(myElement)
}

答案 2 :(得分:1)

这是我为帮助协调异步流程而做的一个小课程:

class CompletionBlock
{
  var completionCode:()->()

  init?(_ execute:()->() )
  { completionCode = execute }

  func deferred() {}

  deinit
  { completionCode() }
}

诀窍是使用要在最后一个异步块之后执行的代码创建CompletionBlock的实例,并在闭包内部引用对象。

let reloadTable = CompletionBlock({ self.tableView.reloadData() })
var posts = [PFObject]()
for post in posts 
{
    post.fetchInBackground(){ reloadTable.deferred() }
}

对象将保持"活着"直到最后一次捕获超出范围。然后对象本身将超出范围,并且它的deinit将被调用,在那时执行你的终结代码。

答案 3 :(得分:0)

以下是使用fetchInBackgroundWithBlock完成后重新加载tableView的示例

    var myArray = [String]()
func fetchData() {
    let userQuery: PFQuery = PFUser.query()!

    userQuery.findObjectsInBackgroundWithBlock({
        (users, error) -> Void in

        var userData = users!

        if error == nil {
            if userData.count >= 1 {
                for i in 0...users!.count-1 {
                    self.myArray.append(userData[i].valueForKey("dataColumnInParse") as! String)
                }
            }
            self.tableView.reloadData()
        } else {
            print(error)
        }
    })
}

我的示例是对用户类的查询,但您明白了......

答案 4 :(得分:0)

我已经对块进行了一些实验,它们似乎在主线程上被调用,这意味着可以在那里进行任何UI更改。我用来测试的代码看起来像这样:

func reloadPosts() {
  PFObject.fetchAllIfNeededInBackground(posts) { 
    [unowned self] (result, error) in

    if let err = error {
      self.displayError(err)
    } 

    self.tableView.reloadData()
  }
}

如果您对是否在主线程上调用了块有疑问,可以使用NSThread类来检查这个

print(NSThread.currentThread().isMainThread)

如果您希望它是防弹的,您可以将reloadData包裹在dispatch_block_t内以确保它位于主线程上

编辑: 如果块在主线程上执行,则文档不会在任何地方声明,但source code非常清楚它是

+ (void)fetchAllIfNeededInBackground:(NSArray *)objects block:(PFArrayResultBlock)block {
    [[self fetchAllIfNeededInBackground:objects] thenCallBackOnMainThreadAsync:block];
}