Swift 3-从主线程更新UI [英] Swift 3- Update UI from main thread

查看:102
本文介绍了Swift 3-从主线程更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在后台线程中加载数据并在主线程上更新tableview / UI。根据这里关于线程的内容,我想知道是否下面的代码是实现它的方法。我正在尝试在用户滚动到特定索引时加载更多数据,并希望确保UI不会因线程而冻结。谢谢!

I wanted to load data in background thread and update tableview/UI on main thread. Based on what's indicated here about threading, I was wondering if the code below is the way to go about it. I'm trying to load more data as user scrolls to a specific index and wanted to make sure the UI is not freezing due to threading. Thank you!

 func loadMore () {
    guard !self.reachedEndOfItems else {
        return
    }

    self.offset = self.offset! + 10
    print("load more offset: \(self.offset)")

    var start = 0
    var end = 0


    isPullToRefresh = false

    let userCreds = UserDefaults.standard

    var getReqString = ""


    if userCreds.bool(forKey: "client_journal") == true || userCreds.bool(forKey: "user_journal") == true {

        var pageNum = ""
        if let pgNum = currentPgNum {
            print(pgNum)
            pageNum = String(pgNum)
        }
        var filterEntryType = ""
        if let entryTypeStr = filtEntryType {
            filterEntryType = entryTypeStr
        }

        var filterUserId = ""
        if let userId = filtUserId {
            filterUserId = userId

        }

        getReqString = "https://gethealthie.com/selected_entries.json?page=\(pageNum)&user_id=\(filterUserId)&entry_type=\(filterEntryType)&entry_filter="


    } else {

        if let pgNum = currentPgNum {
            print(pgNum)

            getReqString = "https://gethealthie.com/entries.json?page=\(pgNum)"
        }

    }


        BXProgressHUD.showHUDAddedTo(self.view)
        let request = Alamofire.request(getReqString, method: .get, headers: [
            "access-token": userCreds.object(forKey: "access-token")! as! String,
            "client": userCreds.object(forKey: "client")! as! String,
            "token-type": userCreds.object(forKey: "token-type")! as! String,
            "uid": userCreds.object(forKey: "uid")! as! String,
            "expiry": userCreds.object(forKey: "expiry")! as! String
            ]).responseJSON { (response:DataResponse<Any>) in
                print(response.response)

                let json = JSON(data: response.data!)
                print(json)

                print("yes")
                print(json.count)


                if userCreds.bool(forKey: "client_journal") == true || userCreds.bool(forKey: "user_journal") == true {
                    self.totalEntries = json["entries"].count

                    let totalEntryCount = json["entries"].count
                    start = 0
                    end = totalEntryCount
                } else {
                    self.totalEntries = json["entries"].count

                    let totalEntryCount = json["entries"].count
                    start = 0
                    end = totalEntryCount
                }

                if  self.totalEntries == 0 {
                    BXProgressHUD.hideHUDForView(self.view);

                } else if end <= self.totalEntries {
                    var jourIdx = 0

                    let newPatient = Patient()
                    let newDietitian = Dietitian()


                    for i in start ..< end {


                        let allEntries = json["entries"]
                        print(allEntries)
                        print("Entry count in loadMore is \(allEntries.count)")

                        let entry = allEntries[i]
                        print(entry)

                        let category = entry["category"]
                        print(category)


                        let name = entry["entry_comments"]
                        let k = name["id"]


                        var indexStr = String(i)

                        //entry attributes
                        self.jsonIdx.add(indexStr)

                        self.type.add(entry["type"].stringValue)
                        self.desc.add(entry["description"].stringValue)
                        self.category.add(entry["category"].stringValue)
                        //food cell- metric stat == healthy int
                        self.metric_stat.add(entry["metric_stat"].stringValue)
                        self.dateCreate.add(entry["created_at"].stringValue)
                        self.viewed.add(entry["viewed"].stringValue)
                        self.seenStatusArr.add(entry["viewed"].stringValue)
                        self.comments.add(entry["entry_comments"].rawValue)
                        self.entryType.add(entry["category"].stringValue)
                        //   "category" : entryType as AnyObject]

                        let posterInfo = entry["poster"]
                        let first = posterInfo["first_name"].stringValue
                        let last = posterInfo["last_name"].stringValue
                        let full = first + " " + last
                        self.captionName.add(full)


                        //food cell subcat
                        self.hungerInt.add(entry["percieved_hungriness"].stringValue)
                        self.prehunger.add(entry["ed_prehunger_string"].stringValue)
                        self.posthunger.add(entry["ed_posthunger_string"].stringValue)
                        self.emotions.add(entry["emotions_string"].stringValue)
                        self.reflection.add(entry["reflection"].stringValue)


                        print(self.comments)
                        self.id.add(entry["id"].stringValue)
                        self.entryImages.add(entry["image_url"].stringValue)


                        if i == end - 1 {
                            userCreds.set(json.count, forKey: "oldJsonCount")

                               BXProgressHUD.hideHUDForView(self.view)

                            DispatchQueue.main.async {
                                self.tableView.reloadData()

                            }
                    }


                } else {
                    var reachedEndOfItems = true
                    BXProgressHUD.hideHUDForView(self.view);
                    print("reached the end")
                }

    }


推荐答案

在此处的代码示例中,您将 reloadData 分派给主队列。但这是不必要的,因为 responseJSON 的关闭已经在主队列上运行,所以不需要分派任何东西。因此,您应该将 reloadData 的调度删除到主队列。

In your code sample here, you are dispatching the reloadData to the main queue. But that is unnecessary because the closure of responseJSON is already running on the main queue, so there's no need to dispatch anything. So, you should remove that dispatch of reloadData to the main queue.

现在,如果您使用 URLSession ,默认为在后台队列上运行闭包,或者如果您明确提供后台队列作为队列参数 responseJSON ,然后,是的,您将 reloadData 发送到主队列。但是,这并不是您需要确保调度到主队列的唯一方法,因为您的模型更新和HUD更新也应该在主队列上运行。但这没有实际意义,因为这个 responseJSON 已经在主队列上运行其完成处理程序。

Now, if you were using URLSession, which defaults to running closures on a background queue or if you explicitly provided a background queue as the queue parameter of responseJSON, then, yes, you'd dispatch reloadData to the main queue. But that's not the only thing you'd need to make sure to dispatch to the main queue, as your model updates and the HUD updates should run on the main queue, too. But that's moot, because this responseJSON is already running its completion handler on the main queue.

然后,在评论中,您稍后会询问是否所有这些都在主队列上运行,是否应该将此全部发送到后台队列,就像在上一个问题(大概是为了避免阻塞主队列)。

Then, in comments, you later ask if all of this is running on the main queue, whether you should dispatch this all to a background queue like you did in a previous question (presumably with the intent of wanting to avoid blocking the main queue).

事实证明这不是必需的(也不可取),因为在 responseJSON 完成处理程序中的响应处理运行时主队列,网络请求本身是异步执行的。如果您在闭包中执行计算密集型操作,则只会将完成处理程序代码分派给后台队列(或将后台队列指定为 responseJSON 的参数)。但您不必担心网络请求阻塞主队列。

It turns out that this is not necessary (nor desirable) because while the processing of the response in the responseJSON completion handler runs on the main queue, the network request, itself, is performed asynchronously. You would only dispatch the completion handler code to a background queue (or specify a background queue as a parameter to responseJSON) if you were doing something computationally intensive in the closure. But you don't have to worry about the network request blocking the main queue.

最重要的是,Alamofire让你很简单,它以异步方式运行请求,但在主队列上运行完成处理程序。当使用 URLSession 时,它消除了大量手动GCD代码。

Bottom line, Alamofire makes this simple for you, it runs the request asynchronously but runs its completion handlers on the main queue. It eliminates much of the manual GCD code that you mess around with when using URLSession.

这篇关于Swift 3-从主线程更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆