ios非同步載入表格式資料及內容不能及時顯示的問題

來源:互聯網
上載者:User

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.