tableView.reloadData()在滚动之前不刷新表,即使使用dispatch_async也是如此

时间:2015-01-27 23:44:02

标签: ios xcode uitableview swift

我有一个相当普遍的问题,但到目前为止解决方案还没有给我预期的结果。

我有一个UITableView,我填充的信息是我在运行时从网络上提取的JSON中解析的。 JSON检索使用func viewDidLoad()函数在NSURLSession.dataTaskWithURL(NSURL, completionHandler)中开始。然后,表格的单元格填充在completionHandler

表中使用的单元格是自定义的,单元格中的所有UI元素都具有通过界面构建​​器设置的默认值。

当表出现时,它完全是空的,尽管它具有正确的单元格高度。我发现这种行为的原因是reloadData函数由于多线程/多处理而没有在正确的时间调用,建议的解决方案是

dispatch_async(dispatch_get_main_queue(), {
    self.tableView.reloadData()
})

代码中的某处允许重新加载正确发生。但是,这只是部分有效。表格看起来像内容一样闪烁,然后立即再次变为空白,直到我滚动。一旦我滚动reloadData函数按预期工作,但只有在我滚动之后。

我已尝试在不同位置(例如reloadData)中使用viewWillAppear功能而没有运气。我可以尝试任何想法或疑难解答提示吗?

编辑#1 - 请求完成处理程序

var listTask = session.dataTaskWithURL(listUrl, completionHandler: {(data, response, error) in
    if error == nil {
        var json:NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: nil) as NSDictionary
        var topGames = json["top"] as [NSDictionary]
        var currGame:NSDictionary
        var toAdd:Game
        for var i=0; i < topGames.count; ++i {
            currGame = topGames[i]["game"] as NSDictionary
            toAdd = Game(
                id: String(currGame["_id"] as CLong),
                name: currGame["name"] as NSString,
                boxArtImageUrl: (currGame["box"] as NSDictionary)["medium"] as NSString,
                boxArtImage: nil,
                isFetchingBoxArt: false,
                totalViewers: topGames[i]["viewers"] as Int,
                totalChannels: topGames[i]["channels"] as Int,
                topChannel: "N/A")
            self.games.append(toAdd)
        }
        dispatch_async(dispatch_get_main_queue(), {
            self.tableView.reloadData()
        })
    }
}

请注意,func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCel中使用了self.games数组来填充单元格中的信息。

编辑#2 - 申请cellForRowAtIndexPath

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell:TopGameListCell = self.tableView.dequeueReusableCellWithIdentifier("topGameCell") as TopGameListCell
    if games.count > 0 {
        var game:Game = games[indexPath.row]
        cell.nameLabel?.text = game.name
        cell.totalViewersLabel.text = String(game.totalViewers)
        cell.totalChannelsLabel.text = String(game.totalChannels)
        cell.topChannelLabel.text = game.topChannel
        if game.boxArtImage != nil {
            cell.boxArtImageView.image = game.boxArtImage
        } else {
            if(!game.isFetchingBoxArt) {
                cell.boxArtImageView.image = placeholderImage
                gatherGameBoxArtImageForCell(game.boxArtImageUrl, indexPath: indexPath)
            }
        }
    }
    return cell;
}

我忘记了我在gatherGameBoxArtImageForCell内开始的额外提取。基本上如果我没有图像,请下载它。图像的if / else似乎导致闪烁发生。如果我让它坐得足够长,它最终会显示出来。我的想法是占位符图像会显示,直到下载图像,然后在下载图像后调用reloadData。这是图片提取completionHandler

var task = session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
    var game = self.games[indexPath.row]
    if error == nil {
        if(game.boxArtImage == nil) {
            var cellForImage:TopGameListCell? = self.tableView.cellForRowAtIndexPath(indexPath) as? TopGameListCell
            if cellForImage != nil {
                self.games[indexPath.row].boxArtImage = UIImage(data: data)
                cellForImage?.boxArtImageView.image = self.games[indexPath.row].boxArtImage
            }
        }
    } else {
        println(error)
    }
    game.isFetchingBoxArt = false
    self.tableView.reloadData()
})

1 个答案:

答案 0 :(得分:0)

看来,当我试图让图像在后台加载时,它正在占据主线程。我所做的是从

改变了以下内容
if(!game.isFetchingBoxArt) {
    cell.boxArtImageView.image = placeholderImage
    gatherGameBoxArtImageForCell(game.boxArtImageUrl, indexPath: indexPath)
}

if(!game.isFetchingBoxArt) {
    cell.boxArtImageView.image = placeholderImage
    dispatch_async(dispatch_get_main_queue(), {
        self.gatherGameBoxArtImageForCell(game.boxArtImageUrl, indexPath: indexPath)
    })
}

在考虑了reloadData dispatch_async的正常解决方案后,我决定这样做。显然我的问题的推理是相同的,所以现在下载的图像是异步的。