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

时间:2017-01-17 23:35:17

标签: swift xcode

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

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():

var checkerVar = false
 override func viewDidLoad() {
            super.viewDidLoad()
            print("It loaded")
            myQueryandAppend(completion: {
                self.tableView.reloadData()
                print("myQuery was called in viewDidLoad()")//never called
                checkerVar = true
            })
            refreshControl = UIRefreshControl()
            refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
            refreshControl.addTarget(self, action: #selector(MainPageVC.refresh(_:)), for: UIControlEvents.valueChanged)
            tableView.addSubview(refreshControl)
            self.navigationController?.navigationBar.isHidden = true
            checkerVar = true //isn't changed on *completion* of the function 
        }

然后是刷新处理程序:

func refresh(_ sender: AnyObject){

        if checkerVar == true{

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

            })
            self.refreshControl.endRefreshing()

        }else{
            self.refreshControl.endRefreshing()
        }

    }

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

2 个答案:

答案 0 :(得分:1)

你的方法" myQueryandAppend"的完成闭包从未被调用,因此完成闭包永远不会被解雇。

所以在你的陈述之后:

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

添加:

completion()

触发关闭。

我相信一旦你解决了这个问题,一切都会很容易到位,因为你的check var会像你期望的那样更新(也许你应该把它命名为isQuerying。

答案 1 :(得分:1)

  

(旁注......不完全确定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()
            }
        }

最后,正如您已经被告知的那样,您未能调用自己的completion处理程序。可是等等。您还在reloadData处理程序中调用completion。现在我们可以删除所有内容,只需拨打completion

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

然而,现在我们遇到了一些困难,因为有两种情况需要考虑。如果if let失败怎么办?我们仍然需要调用完成处理程序,因此我们需要将调用移至completion,以便我们确定无论如何都会发生:

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

随着最后的改变,我认为代码将完成您希望它做的事情。