ios - Swift - 管理任务以填充 UITableView

标签 ios swift uitableview http task

我正在开发的 View 执行以下操作:

  1. 向 API 发送 GET 请求以检索用户列表
  2. 向 API 发送 GET 请求以从用户列表中检索个人资料图片
  3. 在 TableViewCells 中显示图像

但是,我在管理任务和队列时遇到问题。确保在填充 TableView 之前完成所有请求和任务的最佳方法是什么?

代码如下:

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.
    }
    */

}

最佳答案

问题的关键在于以下代码:

dispatch_async(backgroundQueue, {

    self.refreshData()
    self.getImage()

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

        self.tableView.reloadData()

    })
})

NSURLSession 在后台线程中工作,因此当 self.getImage()reloadData< 时,您的 jsonData 为空 被执行。

您可以在此行之后调用 self.getImage()

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

session.dataTaskWithRequest完成 block 中,并在session2.dataTaskWithRequest完成 block 中调用reloadData(在dispatch_get_main_queue上)。

我认为这会解决您的问题。

关于ios - Swift - 管理任务以填充 UITableView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32035474/

相关文章:

ios - 在 Swift 中的代码中向 iOS 应用程序添加启动屏幕(没有 Storyboard或启动板)

ios - iOS 对 Rust 的支持现状如何?

ios - 调用中的参数标签不正确(有 'frame:' ,预期为 'coder:' )

ios - 如何修复文本标签阴影布局

ios - 如何将 UINavigationController 子类附加到它的 UIViewController?

ios - 我如何在 UITableView iPhone 中设计单元格动态?

ios - 有没有办法从容器应用程序中打开 iMessage 扩展程序?

swift - parent 暂停时是否可以对 child 执行操作

uitableview - iOS 12 - Xcode 10 - SWIFT 4.2 - UITableView 左右两侧缺少额外空间

ios - UITableViewCell 附件 View 在 iOS 6 中不显示但在 iOS 7 中显示