获取数据和加载到 UITableView 之间的时间延迟是多少
What is the time delay between getting data and loading to UITableView
我正在从 Api 调用中加载我的 UITableView,但尽管数据检索速度相当快,但在将其加载到 table 之前存在明显的时间延迟。使用的代码如下
import UIKit
class TrackingInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var table : UITableView?
@IBOutlet var indicator : UIActivityIndicatorView?
@IBOutlet var spinnerView : UIView?
var tableArrayList = Array<TableData>()
struct TableData
{
var dateStr:String = ""
var nameStr:String = ""
var codeStr:String = ""
var regionStr:String = ""
init(){}
}
override func viewDidLoad() {
super.viewDidLoad()
table!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
spinnerView?.hidden = false
indicator?.bringSubviewToFront(spinnerView!)
indicator!.startAnimating()
downloadIncidents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func BackToMain() {
performSegueWithIdentifier("SearchToMainSegue", sender: nil)
}
//#pragma mark - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1 //BreakPoint 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableArrayList.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell
cell.incidentDate.text = tableArrayList[indexPath.row].dateStr
cell.incidentText.text = tableArrayList[indexPath.row].nameStr
cell.incidentCode.text = tableArrayList[indexPath.row].codeStr
cell.incidentLoctn.text = tableArrayList[indexPath.row].regionStr
return cell //BreakPoint 4
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
AppDelegate.myGlobalVars.gIncName = tableArrayList[indexPath.row].nameStr
AppDelegate.myGlobalVars.gIncDMA = tableArrayList[indexPath.row].codeStr
performSegueWithIdentifier("SearchResultsToDetailSegue", sender: nil)
}
func alertView(msg: String) {
let dialog = UIAlertController(title: "Warning",
message: msg,
preferredStyle: UIAlertControllerStyle.Alert)
dialog.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
presentViewController(dialog,
animated: false,
completion: nil)
}
func downloadIncidents()
{
var event = AppDelegate.myGlobalVars.gIncName
var DMA = AppDelegate.myGlobalVars.gIncDMA
if event == "Enter Event Name" {
event = ""
}
if DMA == "Enter DMA" {
DMA = ""
}
let request = NSMutableURLRequest(URL: NSURL(string: "http://incident-tracker-api-uat.herokuapp.com/mobile/events?name=" + event)!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error != nil {
self.alertView("Error - " + error!.localizedDescription)
}
else {
do {
var incidentList: TableData
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
incidentList = TableData()
if let nameStr = dict["name"] as? String {
incidentList.nameStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.codeStr = codeStr
}
if let dateStr = dict["supplyOutageStart"] as? String {
let tmpStr = dateStr
let index = tmpStr.startIndex.advancedBy(10)
incidentList.dateStr = tmpStr.substringToIndex(index)
}
if let regionStr = dict["region"] as? String {
incidentList.regionStr = regionStr
}
self.tableArrayList.append(incidentList)
}
}
self.spinnerView?.hidden = true
self.indicator?.stopAnimating()
self.table?.reloadData() //BreakPoint 3
}
}catch let err as NSError
{
self.alertView("Error - " + err.localizedDescription)
}
}
})
task.resume() //BreakPoint 1
}
当class为运行时,它先命中断点1,然后命中断点2,然后快速转到断点3,然后再次转到断点2。然后在它到达 cellForRowAtIndexPath() 中的断点 4 之前有大约 20 到 30 秒的延迟,并且数据被加载到 UITableView 中。之后视图很快显示出来。
从 Web 服务中检索数据的速度非常快,那么为什么在将数据加载到 table 视图之前会有明显的延迟? Web Service方法是否需要线程化?
table 视图应在您调用 tableView.reloadData()
后几分之一秒内开始重新加载。
但是,如果您从后台线程进行 UI 调用,结果为 "undefined"。在实践中,我看到的一个常见影响是 UI 更改需要非常长的时间才能真正生效。第二个最可能的副作用是崩溃,但其他奇怪的副作用也是可能的。
NSURLSession
调用的完成处理程序默认在后台线程上 运行。因此,您需要将所有 UI 调用包装在对 dispatch_async(dispatch_get_main_queue())
的调用中(现在是 Swift 3 中的 DispatchQueue.main.async()
。)
(如果你正在做计算密集型工作,比如 JSON 在你的闭包中解析,最好从后台进行,这样你就不会阻塞主线程。然后只做 UI 从主线程调用。)
在您的情况下,您希望包装标有 "breakpoint 3" 的 3 行代码(所有 UI 调用)以及对 self.alertView()
[=16 的其他调用=]
请注意,如果您确定完成闭包中的代码很快,您可以简单地将闭包的整个主体包装在对 dispatch_async(dispatch_get_main_queue())
.
的调用中
您正在后台线程中获取服务器响应,因此您需要在 UI 线程上调用 reloadData()
函数。我怀疑等待时间可能会有所不同,具体取决于您是否与应用程序交互,该应用程序有效地调用了 UI 线程,那是 table 实际显示新数据的时间。
简而言之,您需要用
包裹 self.table?.reloadData() //BreakPoint 3
dispatch_async(dispatch_get_main_queue()) {
// update some UI
}
最终结果会是
前 Swift 3.0
dispatch_async(dispatch_get_main_queue()) {
self.table?.reloadData()
}
Post Swift 3.0
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
只需确保在 Dispatch 主异步中重新加载 tableview,即可立即获取数据
我正在从 Api 调用中加载我的 UITableView,但尽管数据检索速度相当快,但在将其加载到 table 之前存在明显的时间延迟。使用的代码如下
import UIKit
class TrackingInfoController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet var table : UITableView?
@IBOutlet var indicator : UIActivityIndicatorView?
@IBOutlet var spinnerView : UIView?
var tableArrayList = Array<TableData>()
struct TableData
{
var dateStr:String = ""
var nameStr:String = ""
var codeStr:String = ""
var regionStr:String = ""
init(){}
}
override func viewDidLoad() {
super.viewDidLoad()
table!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
spinnerView?.hidden = false
indicator?.bringSubviewToFront(spinnerView!)
indicator!.startAnimating()
downloadIncidents()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func BackToMain() {
performSegueWithIdentifier("SearchToMainSegue", sender: nil)
}
//#pragma mark - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1 //BreakPoint 2
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableArrayList.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell
cell.incidentDate.text = tableArrayList[indexPath.row].dateStr
cell.incidentText.text = tableArrayList[indexPath.row].nameStr
cell.incidentCode.text = tableArrayList[indexPath.row].codeStr
cell.incidentLoctn.text = tableArrayList[indexPath.row].regionStr
return cell //BreakPoint 4
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
AppDelegate.myGlobalVars.gIncName = tableArrayList[indexPath.row].nameStr
AppDelegate.myGlobalVars.gIncDMA = tableArrayList[indexPath.row].codeStr
performSegueWithIdentifier("SearchResultsToDetailSegue", sender: nil)
}
func alertView(msg: String) {
let dialog = UIAlertController(title: "Warning",
message: msg,
preferredStyle: UIAlertControllerStyle.Alert)
dialog.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
presentViewController(dialog,
animated: false,
completion: nil)
}
func downloadIncidents()
{
var event = AppDelegate.myGlobalVars.gIncName
var DMA = AppDelegate.myGlobalVars.gIncDMA
if event == "Enter Event Name" {
event = ""
}
if DMA == "Enter DMA" {
DMA = ""
}
let request = NSMutableURLRequest(URL: NSURL(string: "http://incident-tracker-api-uat.herokuapp.com/mobile/events?name=" + event)!,
cachePolicy: .UseProtocolCachePolicy,
timeoutInterval: 10.0)
request.HTTPMethod = "GET"
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error != nil {
self.alertView("Error - " + error!.localizedDescription)
}
else {
do {
var incidentList: TableData
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments) as? Array<Dictionary<String, AnyObject>> {
for item in json {
if let dict = item as? Dictionary<String, AnyObject> {
incidentList = TableData()
if let nameStr = dict["name"] as? String {
incidentList.nameStr = nameStr
}
if let codeStr = dict["dma"] as? String {
incidentList.codeStr = codeStr
}
if let dateStr = dict["supplyOutageStart"] as? String {
let tmpStr = dateStr
let index = tmpStr.startIndex.advancedBy(10)
incidentList.dateStr = tmpStr.substringToIndex(index)
}
if let regionStr = dict["region"] as? String {
incidentList.regionStr = regionStr
}
self.tableArrayList.append(incidentList)
}
}
self.spinnerView?.hidden = true
self.indicator?.stopAnimating()
self.table?.reloadData() //BreakPoint 3
}
}catch let err as NSError
{
self.alertView("Error - " + err.localizedDescription)
}
}
})
task.resume() //BreakPoint 1
}
当class为运行时,它先命中断点1,然后命中断点2,然后快速转到断点3,然后再次转到断点2。然后在它到达 cellForRowAtIndexPath() 中的断点 4 之前有大约 20 到 30 秒的延迟,并且数据被加载到 UITableView 中。之后视图很快显示出来。
从 Web 服务中检索数据的速度非常快,那么为什么在将数据加载到 table 视图之前会有明显的延迟? Web Service方法是否需要线程化?
table 视图应在您调用 tableView.reloadData()
后几分之一秒内开始重新加载。
但是,如果您从后台线程进行 UI 调用,结果为 "undefined"。在实践中,我看到的一个常见影响是 UI 更改需要非常长的时间才能真正生效。第二个最可能的副作用是崩溃,但其他奇怪的副作用也是可能的。
NSURLSession
调用的完成处理程序默认在后台线程上 运行。因此,您需要将所有 UI 调用包装在对 dispatch_async(dispatch_get_main_queue())
的调用中(现在是 Swift 3 中的 DispatchQueue.main.async()
。)
(如果你正在做计算密集型工作,比如 JSON 在你的闭包中解析,最好从后台进行,这样你就不会阻塞主线程。然后只做 UI 从主线程调用。)
在您的情况下,您希望包装标有 "breakpoint 3" 的 3 行代码(所有 UI 调用)以及对 self.alertView()
[=16 的其他调用=]
请注意,如果您确定完成闭包中的代码很快,您可以简单地将闭包的整个主体包装在对 dispatch_async(dispatch_get_main_queue())
.
您正在后台线程中获取服务器响应,因此您需要在 UI 线程上调用 reloadData()
函数。我怀疑等待时间可能会有所不同,具体取决于您是否与应用程序交互,该应用程序有效地调用了 UI 线程,那是 table 实际显示新数据的时间。
简而言之,您需要用
包裹self.table?.reloadData() //BreakPoint 3
dispatch_async(dispatch_get_main_queue()) {
// update some UI
}
最终结果会是
前 Swift 3.0
dispatch_async(dispatch_get_main_queue()) {
self.table?.reloadData()
}
Post Swift 3.0
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
只需确保在 Dispatch 主异步中重新加载 tableview,即可立即获取数据