图像无法在表格视图中显示

时间:2017-05-11 06:26:13

标签: swift uitableview nsurlsessiondatatask

我创建了一个带有自定义单元格的tableView,每个单元格都有一个图像。

在模型类中,我创建了一个func mainPulatesData()来使用URLSession dataTask方法从url中检索数据,并将数据转换为完成处理程序块中的UIImage,然后将图像添加到UIImage数组的变量。

检索数据并将其添加到UIImage数组中的过程在DispatchQueue.global(qos: .userInitiated).async块中执行。根据打印消息,图像确实被添加到数组中。

但是,即使我在tableView控制器中创建了一个模型类实例,并调用mainPulatesData()中的viewDidlLoad,图像也没有显示在表格中。

基于表视图控制器类中的其他打印消息,我发现它甚至可以添加到模型类中的数组中,但似乎对tableView控制器中的模型类实例不起作用。

这是获取图像数据的模型类中的代码:

func mainPulatesData() {
    let session = URLSession.shared
    if myURLs.count > 0{
        print("\(myURLs.count) urls")
        for url in myURLs{
            let task = session.dataTask(with: url, completionHandler: { (data,response, error)  in
                let imageData = data
                DispatchQueue.global(qos: .userInitiated).async {
                    if imageData != nil{
                        if let image = UIImage(data: imageData!){
                            self.imageList.append(image)
                            print("\(self.imageList.count) images added.")
                        }
                    }
                    else{
                        print("nil")
                    }
                }
            })
            task.resume()   
        }
    }
}

这是视图控制器中用于创建模型实例的代码:

override func viewDidLoad() {
    super.viewDidLoad()
    myModel.mainPulatesURLs()
    myModel.mainPulatesData()
    loadImages()
}

private func loadImages(){
    if myModel.imageList.count > 0{
        tableView.reloadData()
    }
    else{
        print("data nil")
    }
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return myModel.imageList.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath) as! ImageTableViewCell
    if myModel.imageList.count > 0{
        let image = myModel.imageList[indexPath.row]
        cell.tableImage = image
        return cell

    }
    return cell
}

3 个答案:

答案 0 :(得分:0)

您应该记下函数调用的顺序:

myModel.mainPulatesURLs() --> populates myURLs
myModel.mainPulatesData() --> populates image from myURLs in forloop asynchronously.
loadImages() --> called asynchronously.

当您从myModel.mainPulatesData()加载已经loadImages() myModel.imageList loadImages()时仍然为空的图片时,

您应该在myModel.mainPulatesData()回调后或当您确定已加载的图片时调用dispatch_group_t

您可以使用import UIKit var myURLs: [String] = ["urlA", "urlB", "urlC", "urlD"] // we define the group for our asynchronous fetch. also works in synchronous config var fetchGroup = DispatchGroup() for urlString in myURLs { // for every url fetch we define, we will call an 'enter' to issue that there is a new block for us to wait or monitor fetchGroup.enter() // the fetch goes here let url = URL(string: urlString)! URLSession.shared.downloadTask(with: URLRequest(url: url), completionHandler: { (urlReq, urlRes, error) in // do your download config here... // now that the block has downloaded the image, we are to notify that it is done by calling 'leave' fetchGroup.leave() }).resume() } // now this is where our config will be used. fetchGroup.notify(queue: DispatchQueue.main) { // reload your table here as all of the image were fetched regardless of download error. } 配置回调。

根据要求提供:

scoped_lock

答案 1 :(得分:0)

图像不会显示,因为您在后台线程中下载(异步),并且loadImages()被同步调用。这意味着在loadImage()执行之前调用myModel.mainPulatesData(),因此在下载图像时,tableview未更新(reloadData()未被调用)。您应创建Protocol以通知UIViewController,已下载数据,或使用Completion Handler

我正在使用的处理程序的简单示例,我在我的viewDidLoad中调用它,它从服务器请求数据并返回[Reservation]?的数组

 ReservationTableModule.requestAllReservations { [weak self] reservations in
            guard let `self` = self else {
                return
            }

            guard let `reservations` = `reservations` else {
                return
            }
            self.reservations = reservations
            .reservationsTableView.reloadData()
        }

这是实际的请求函数

class func requestAllReservations(handler: @escaping ([Reservation]?) -> Void) {

    let url = "reservations/all"

    APIModel.shared.requestWithLocation(.post, URL: url, parameters: nil) { data in
        let reservations = data?["reservations"].to(type: Reservation.self) as? [Reservation]
        handler(reservations)
    }
}

handler: @escaping ([Reservation]?) -> Void被称为完成处理程序,您应该,我想将其设为handler: @escaping ([UIImage]?) -> Void并在您的数据下载后调用handler(reservations)

答案 2 :(得分:0)

原因是,在您imageList之后调用[{1}}时,图片或cellForRowAt尚未就绪。

一个好的做法是在开头使用占位符图像,只在表视图单元格可见时加载图像而不是一次加载所有内容。类似的东西:

reloadData()