Swift 在允许用户手动刷新页面之前,如何确保viewDidLoad()已完成?

Swift 在允许用户手动刷新页面之前,如何确保viewDidLoad()已完成?,swift,xcode,Swift,Xcode,我有一个重新加载数据的应用程序(通过运行两个查询,将查询到的信息附加到数组,以及重新加载tableview数据)。这两个查询都设置为在viewDidLoad()上运行的函数,但也链接到一个刷新函数(用户可以通过拉动刷新手动激活该函数)。查询工作正常,但是,当查询函数由viewdiload()运行(但尚未完成)时,偶尔会出现问题,并且用户试图在完成之前拉刷新。。。重复项被添加到数组中,我希望避免这种情况。我的想法是最初将checking变量设置为false,在viewDidLoad()完成后将其更

我有一个重新加载数据的应用程序(通过运行两个查询,将查询到的信息附加到数组,以及重新加载tableview数据)。这两个查询都设置为在
viewDidLoad()
上运行的函数,但也链接到一个刷新函数(用户可以通过拉动刷新手动激活该函数)。查询工作正常,但是,当查询函数由
viewdiload()
运行(但尚未完成)时,偶尔会出现问题,并且用户试图在完成之前拉刷新。。。重复项被添加到数组中,我希望避免这种情况。我的想法是最初将checking变量设置为false,在viewDidLoad()完成后将其更改为true,并且只允许pull to refresh函数在变量更改为true后工作。以下是功能的设置:

func myQueryandAppend(completion: (() -> Void)?){
        myCreatorArray.removeAll(keepingCapacity: true)
        //repeated for all arrays
        let myQuery = PFQuery(className: "Posts")
        myQuery.whereKey("User", equalTo: currentUserId)
        myQuery.findObjectsInBackground { (objects, error) in
            if let objectss = objects{
                for object in objectss {
                    //append the arrays
                    self.tableView.reloadData()
                }
            }
       })
}
另一个函数本质上与此函数相同,但提取稍有不同的信息并附加不同的数组。(旁注…不完全确定
self.tableView.reloadData()
是否位于正确位置…)

这是viewDidLoad():

然后刷新处理程序:

func refresh(_ sender: AnyObject){

        if checkerVar == true{

            myQueryandAppend(completion: {
                self.tableView.reloadData()
                self.refreshControl.endRefreshing()

            })
            self.refreshControl.endRefreshing()

        }else{
            self.refreshControl.endRefreshing()
        }

    }
问题是,使用checkerVar时,viewDidLoad()闭包中completion内的实例永远不会被调用(上面的print语句永远不会被记录),我相信viewDidLoad()底部的第二个实例会立即完成,而不会真正等待函数完成。此外,任何
(完成:{})
中的打印语句都不会被记录。 所以:1。为什么不调用补全中的print语句,以及(更重要的)2。如何使checkerVar仅在
viewDidLoad()
完成后才更改为true?

您的方法“MyQueryAndPend”的完成闭包从未被调用,因此完成闭包从未被触发

因此,在您的for声明之后:

for object in objectss {
    //append the arrays
    self.tableView.reloadData()
}
加:

触发关闭

我相信,一旦您解决了这个问题,一切都会很容易到位,因为您的check var将按照您的预期进行更新(也许您应该将其命名为类似isQuery的名称)

(旁注…不完全确定
self.tableView.reloadData()
是否位于正确位置…)

不是。您多次调用
reloadData
,对
objects
中的每个对象调用一次。这是浪费。您应该这样写:

        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
            self.tableView.reloadData()
        }
另外,我不指望这段代码在主线程上运行,但您必须确保在主线程上调用了
reloadData

        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
最后,正如您已经被告知的,您无法调用自己的
完成处理程序。请稍候。您还在
完成处理程序中调用
重新加载数据
。因此,现在我们可以删除所有这些,只需调用
完成处理程序即可:

        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
            DispatchQueue.main.async {
                completion()
            }
        }

现在,我们遇到了一个小小的困难,因为有两个案例需要考虑。如果<代码>如果失败了,我们仍然需要调用完成句柄,所以我们需要把调用移动到<代码>完成< /代码>,这样我们确信不管发生什么:

它都会发生。
        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
        }
        DispatchQueue.main.async {
            completion()
        }

有了最后的更改,我想代码将完成您希望它做的事情。

感谢您的快速响应。我将
completion()
直接放在结束之后?不用担心。不,您想放completion()在闭包内部,基本上是为了在收到查询闭包时触发完成闭包。是否需要在主线程中运行所有
.reloadData()
无论何时你以任何方式、形状或形式触摸界面,你都必须处于主线程上。否则,小个子男人会在晚上来到你家偷你的内裤。而且,正如你正确地说的那样,
checkerVar
内部的更改
viewDidLoad
显然会在调用完成处理程序之前发生,所以请不要在如果你不了解它是如何工作的,你需要在“异步”上搜索。
        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
            DispatchQueue.main.async {
                completion()
            }
        }
        if let objectss = objects{
            for object in objectss {
                //append the arrays
            }
        }
        DispatchQueue.main.async {
            completion()
        }