Swift 3-从主线程更新UI
我想在后台线程中加载数据,并在主线程上更新tableview / UI。 根据这里所说的关于线程的内容,我想知道下面的代码是否可以解决这个问题。 我试图加载更多的数据作为用户滚动到一个特定的索引,并希望确保UI不冻结由于线程。 谢谢!
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
的closures已经在主队列上运行了,所以不需要发送任何东西。 所以,你应该把这个reloadData
分派移除到主队列中。
现在,如果您使用的是URLSession
,默认情况下在后台队列上运行闭包,或者如果您明确提供了一个后台队列作为responseJSON
的queue
参数,那么是的,您需要将reloadData
分派到主队列中。 但是,这不是唯一需要确保分派到主队列的事情,因为您的模型更新和HUD更新也应该在主队列上运行。 但是这是没有实际意义的,因为这个responseJSON
已经在主队列上运行完成处理程序了。
然后,在注释中,你稍后会问,如果所有这些都在主队列上运行,是否应该像上一个问题那样将这个全部调度到后台队列(可能是为了避免阻塞主队列) 。
事实certificate,这不是必需的(也不是理想的),因为虽然responseJSON
完成处理程序中的responseJSON
处理在主队列上运行,但是networking请求本身是asynchronous执行的。 如果您在闭包中进行大量计算,则只会将完成处理程序代码分派到后台队列(或指定背景队列作为responseJSON
的参数)。 但是您不必担心阻塞主队列的networking请求。
底线,Alamofire使这个简单的你,它运行请求asynchronous,但在主队列上运行其完成处理程序。 它消除了使用URLSession
时大量的手动GCD代码。