简体   繁体   中英

Swift - Manage tasks to populate UITableView

The view I'm developing does the following:

  1. Sends a GET request to the API to retrieve a list of users
  2. Sends GET requests to the API to retrieve profile images from the list of users
  3. Display the images in TableViewCells

However, I'm having problem managing the tasks and the queues. What is the best way to be sure that all the requests and tasks are done before populating the Table View?

Here's the code:

import UIKit

class homeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    var jsonData : [NSDictionary] = [NSDictionary]()
    var imageUrls: NSDictionary = NSDictionary()
    var urlsArray: [NSURL] = [NSURL]()

    override func viewDidLoad() {
        super.viewDidLoad()    

        let qualityOfServiceClass = QOS_CLASS_BACKGROUND
        let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
        dispatch_async(backgroundQueue, {

            self.refreshData()
            self.getImage()

            dispatch_async(dispatch_get_main_queue(), { () -> Void in

                self.tableView.reloadData()

            })
        })

    }

    override func viewWillAppear(animated: Bool) {

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return jsonData.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        var type = jsonData[indexPath.row]["type"] as! Int

        for typej in jsonData {

            let t : Int = typej["type"] as! Int

            println("type : \(t)")

        }

        if type == 1 {

            let cell1 : cellTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! cellTableViewCell

           /* //If images url are retrieved, load them. Otherwise, load the placeholders
            if self.urlsArray.isEmpty == false {

                println("Tiè: \(self.urlsArray[indexPath.row])")

                if let data = NSData(contentsOfURL: self.urlsArray[indexPath.row]) {

                    cell1.profileImg?.image = UIImage(data: data)

                }

            } else {

                cell1.profileImg?.image = UIImage(named: "placeholder.png")

            }*/

            let block: SDWebImageCompletionBlock! = {

                (image: UIImage!, error: NSError!, cacheType: SDImageCacheType, imageURL: NSURL!) -> Void in

                println(self)
            }

            println("url Array: \(self.urlsArray)")

            let url = NSURL(string: "http://adall.ga/s/profile-1439584252497.png")

            if UIApplication.sharedApplication().canOpenURL(urlsArray[indexPath.row])   {
                cell1.profileImg.sd_setImageWithURL(urlsArray[indexPath.row], completed: block)

            } else {

                cell1.profileImg.sd_setImageWithURL(url, completed: block)

            }


            cell1.testLbl.text = (self.jsonData[indexPath.row]["author"] as? String)!

            return cell1

        } else {

            let cell2 : cell2TableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell2") as! cell2TableViewCell

            return cell2
        }
    }

    func refreshData()   {

        let requestURL = NSURL(string:"http://adall.ga/api/feeds/author/mat/0")!

        var request = NSMutableURLRequest(URL: requestURL)
        request.HTTPMethod = "GET"

        request.addValue(userToken, forHTTPHeaderField: "tb-token")

        let session = NSURLSession.sharedSession()

        let task = session.dataTaskWithRequest(request) {
            data, response, error in

            println(response)

            var dataString = NSString(data: data, encoding: NSUTF8StringEncoding)

            println(dataString)

            //let jsonResult : NSDictionary = (NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary)!
            //jsonData = (NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers , error: nil) as? NSArray)!

            self.jsonData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil) as! [NSDictionary]

        }

        task.resume()

        var index: Int
        for index = 0; index < 10000; ++index {
            print("Index: \(index), Task state: \(task.state)")
        }
    }

    func getImage() {

        var i = 0

        for jsonSingleData in jsonData {

            let author = jsonSingleData["author"] as! String       

            let requestURL2 = NSURL(string: "http://adall.ga/api/users/" + author + "/image")!

            var request2 = NSMutableURLRequest(URL: requestURL2)
            request2.HTTPMethod = "GET"

            request2.addValue(userToken!, forHTTPHeaderField: "tb-token")

            let session2 = NSURLSession.sharedSession()

            let task2 = session2.dataTaskWithRequest(request2) {
                data, response, error in

                println("response= \(response)")

                var dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
                println(dataString)

                self.imageUrls = (NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as! NSDictionary)

                if self.imageUrls["url"] != nil {
                //check if exists
                    let imageUrl = self.imageUrls["url"] as! String

                    let url = NSURL(string: "http://" +  imageUrl)

                    self.urlsArray.append(url!)

                } else {

                    let imageUrl = "http://shackmanlab.org/wp-content/uploads/2013/07/person-placeholder.jpg"

                    let url = NSURL(string: imageUrl)

                    self.urlsArray.append(url!)

                }

            }

            task2.resume()
            self.tableView.reloadData()
        }
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

The point of the issue is the following code:

dispatch_async(backgroundQueue, {

    self.refreshData()
    self.getImage()

    dispatch_async(dispatch_get_main_queue(), { () -> Void in

        self.tableView.reloadData()

    })
})

The NSURLSession working in the background thread, so your jsonData is empty when the self.getImage() and reloadData are executed.

You can call the self.getImage() after this line

self.jsonData = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments, error: nil) as! [NSDictionary]

in the session.dataTaskWithRequest completed block and calls reloadData (on the dispatch_get_main_queue) in the completed block of the session2.dataTaskWithRequest .

I think this will solved your issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM