你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS7技巧 >> ios異步加載表格數據及內容不能及時顯示的問題

ios異步加載表格數據及內容不能及時顯示的問題

編輯:IOS7技巧
異步加載我們在網頁開發中叫做幫ajax了,其實是一樣的這裡我們在ios開發中也會碰到異步加載了,下面我們來看一些關於異步加載的例子與碰到的問題解決辦法吧。

異步事件,就是說這一個代碼或者代碼塊,並不會阻塞程序的運行,程序會立即執行下一條語句,而這條語句,會在相應的方法調用結束之後,執行它自身的回調函數發送一些信號,來表明這個異步事件完成。就像你約會提前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()
    }
}

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved