最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
ios异步加载表格数据及内容不能及时显示的问题
时间:2022-06-25 23:40:16 编辑:袖梨 来源:一聚教程网
异步事件,就是说这一个代码或者代码块,并不会阻塞程序的运行,程序会立即执行下一条语句,而这条语句,会在相应的方法调用结束之后,执行它自身的回调函数发送一些信号,来表明这个异步事件完成。就像你约会提前1小时到见面地点,先去买点东西踩点什么的(……),等GF/BF到了之后短信通知你,你就立即回来。而不是一直在原地等到对方过来(……)
最早使用异步开发,是在使用JavaScript来开发Web前端的时候,XMLHttpRequest或者jQuery的$.ajax中,都会用到回调函数,来指明成功或者失败之后的处理方法。当对应的网络请求得到响应之后,会调用响应的成功或者失败的回调函数,然后执行里面相应的方法,这大大提升了前端的效率,不会在网络请求时整个页面卡住,而且也不需要一次次轮询看是否有响应,简化了代码的复杂性。
这点Node.js中更为常见,不过也更能表现中滥用异步事件编程的问题。新人使用Node.js总会发现基本任何东西都是异步的,数据库是异步的,IO文件操作是异步的,Session读写是异步的,甚至获得Request对象都是异步的。这就导致很多人一直在嵌套回调函数,导致了著名的Callback Hell
在Node.js中,解决方案有非常成熟的Async,更有号称能用同步思维写异步的Promises,都是非常棒的解决方案。前者的本质就是一个自动生成回调的封装……,后者则是一个真正意义上的全新的解决方案。
而在Swift和iOS开发中,也有必须用到异步事件编程的地方。除了View层的简单UI和Controller之间的交互以外(这部分一般不需要手写代码处理异步交互或者顺序),其他很多地方需要这些知识。例如网络请求的异步调用,请求队列的处理(虽然可以一个网络请求就是一个线程,但这种方法的效率不高,而且容易导致线程间冲突),SQLite数据库大量数据的读写,本地存储的大量数据读写,复杂UI的渲染顺序等等……这些都是需要进行异步编程的,而不能让同步的代码阻塞住整个应用或者UI。
举个例子,这里是一个UI顺序加载的动画……
func schoolLifeClicked()
{
var mydrawerController = self.mm_drawerController //一个用TableView实现的应用侧边栏抽屉View
let schoolLifeViewController:SchoolLifeViewController = SchoolLifeViewController(nibName: "SchoolLifeViewController", bundle: nil)
let navSchoolLifeViewController = CommonNavViewController(rootViewController: schoolLifeViewController)
self.mm_drawerController.toggleDrawerSide(MMDrawerSide.Left, animated: true, completion:{(complete) in
if complete{//如果成功拉出抽屉
mydrawerController.setCenterViewController(navSchoolLifeViewController, withCloseAnimation: true, completion: nil)//设置主视图
mydrawerController.closeDrawerAnimated(true, completion:nil)//关闭抽屉
}
})//一个闭包,成功后调用
}
可以看到,Swift很多时候也可以依靠回调函数,把一个闭包扔进去当参数,然后执行,从而控制这种异步事件的流程……
但是,这种方法写起来,就会回到和JS那种匿名函数闭包扔进去当参数一样,小范围用还可以,一旦你要进行复杂的流程控制,比如一系列异步事件,AB同时执行,AB同时完成后执行C,C执行完成后执行D……这种控制下写出来的代码和JavaScript的callback hell是一样的,难以维护。
怎么办呢?其实自己实现一个语法糖或者函数队列来执行也不难,不过这里可以推荐一下GitHub上非常厉害的库,大家有怎么使用呢?参考人家的Readme,用语法糖可以很简单的使用:
Async.userInitiated {
println("start")
}.main {
println("1")
}.background {
println("2")
}.background {
println("2 all the same")
}.main {
println("stop")
}由于异步事件的特点,所以整个输出可能就会是
start
1
2
stop
2 all the same不要大惊小怪哦。利用这个就可以从繁重的callback中解放出来,简单的处理异步事件的顺序,并且获得很高的性能,这也是网络请求和数据库访问等必须要考虑的地方……
ios异步加载表格数据,内容不能及时显示的问题
1,问题描述
我们使用 tableView 的时候,又是表格内容是异步加载的。比如从网络获取数据显示、或是开启个线程队列定时刷新加载表格数据。
(1)比如我们要加载的数据如下:
[
{
"name": "hangge",
"age": 100,
},
{
"name": "big boss",
"age": 1,
},
{
"name": "batman",
"age": 12,
}
]
(2)使用 NSURLSession 获取远程数据后,调用 tableView的reloadData() 方法重新加载数据。
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var ctrlnames:NSArray = []
var tableView:UITableView?
override func viewDidLoad() {
super.viewDidLoad()
//创建表视图
self.tableView = UITableView(frame: self.view.frame, style:UITableViewStyle.Plain)
self.tableView!.delegate = self
self.tableView!.dataSource = self
//创建一个重用的单元格
self.tableView!.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "SwiftCell")
self.view.addSubview(self.tableView!)
//创建NSURL对象
let urlString:String="http://www.hangge.com/code/test.php"
let url:NSURL! = NSURL(string:urlString)
//创建请求对象
let request:NSURLRequest = NSURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request,
completionHandler: {(data, response, error) -> Void in
if error != nil{
print(error?.code)
print(error?.description)
}else{
self.ctrlnames = try! NSJSONSerialization.JSONObjectWithData(data!,
options: NSJSONReadingOptions.MutableContainers) as! NSArray
self.tableView?.reloadData()
}
}) as NSURLSessionTask
//使用resume方法启动任务
dataTask.resume()
}
//在本例中,只有一个分区
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
//返回表格行数(也就是返回控件数)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.ctrlnames.count
}
//创建各单元显示内容(创建参数indexPath指定的单元)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell
{
//为了提供表格显示性能,已创建完成的单元需重复使用
let identify:String = "SwiftCell"
//同一形式的单元格重复使用,在声明时已注册
let cell = tableView.dequeueReusableCellWithIdentifier(identify,
forIndexPath: indexPath) as UITableViewCell
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
let item = self.ctrlnames[indexPath.row] as! NSDictionary
cell.textLabel?.text = item.objectForKey("name") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
(3)但会发现数据加载完毕后表格还是空白的,拖动一点点表格数据就显示出来了。
原文:Swift - 异步加载表格数据,内容不能及时显示的问题解决 原文:Swift - 异步加载表格数据,内容不能及时显示的问题解决
2,解决办法
reloadData() 方法需要在主线程中调用,这样表格数据就能及时更新。(代码高亮出为修改的地方)
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var ctrlnames:NSArray = []
var tableView:UITableView?
override func viewDidLoad() {
super.viewDidLoad()
//创建表视图
self.tableView = UITableView(frame: self.view.frame, style:UITableViewStyle.Plain)
self.tableView!.delegate = self
self.tableView!.dataSource = self
//创建一个重用的单元格
self.tableView!.registerClass(UITableViewCell.self,
forCellReuseIdentifier: "SwiftCell")
self.view.addSubview(self.tableView!)
//创建NSURL对象
let urlString:String="http://www.hangge.com/code/test.php"
let url:NSURL! = NSURL(string:urlString)
//创建请求对象
let request:NSURLRequest = NSURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request,
completionHandler: {(data, response, error) -> Void in
if error != nil{
print(error?.code)
print(error?.description)
}else{
self.ctrlnames = try! NSJSONSerialization.JSONObjectWithData(data!,
options: NSJSONReadingOptions.MutableContainers) as! NSArray
dispatch_async(dispatch_get_main_queue(), {
self.tableView?.reloadData()
return
})
}
}) as NSURLSessionTask
//使用resume方法启动任务
dataTask.resume()
}
//在本例中,只有一个分区
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
//返回表格行数(也就是返回控件数)
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.ctrlnames.count
}
//创建各单元显示内容(创建参数indexPath指定的单元)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell
{
//为了提供表格显示性能,已创建完成的单元需重复使用
let identify:String = "SwiftCell"
//同一形式的单元格重复使用,在声明时已注册
let cell = tableView.dequeueReusableCellWithIdentifier(identify,
forIndexPath: indexPath) as UITableViewCell
cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
let item = self.ctrlnames[indexPath.row] as! NSDictionary
cell.textLabel?.text = item.objectForKey("name") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
相关文章
- 王者荣耀侦探能力大测试攻略 王者荣耀侦探能力大测试怎么过 11-22
- 无期迷途主线前瞻兑换码是什么 11-22
- 原神欧洛伦怎么培养 11-22
- 炉石传说网易云音乐联动怎么玩 11-22
- 永劫无间手游确幸转盘怎么样 11-22
- 无期迷途主线前瞻兑换码是什么 无期迷途主线前瞻直播兑换码介绍 11-22