ios - reloadData 之后未调用 cellForRowAtIndexPath 但 numberOfRowsInSection 调用

标签 ios swift uitableview

在我当前的项目中,我正在尝试从 REST 端点获取新闻,并且我想在网络请求完成后刷新 UITableView。所以我调用了 reloadData() 但不幸的是 cellForRowAtIndexPath 没有被调用,但是 numberOfRowsInSection 被调用并返回了正确的项目数。

按照我的代码精简到相关部分:

class NewsTableViewController: UIViewController {

    private var newsItems: Array<NewsItem>!
    private var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        newsItems = []
        addDummyItem()
        prepareTableView()
        getNews()
    }

    func addDummyItem(){
        let newsItem = NewsItem()
        newsItem.dateString = "12th May"
        newsItem.title = "Lorem ipsum"
        newsItem.imgUrl = "URL"
        newsItem.url = "URL"
        newsItem.message = "Lorem ipsum dolor sit amet"
        self.newsItems.append(newsItem)
    }

    func getNews(){
        let url = NSURL(string: "http://someurl.com/news")
        let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: url!)
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(urlRequest) { data, response, error in
            guard data != nil && error == nil else {
                print(error)
                return
            }

            guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else {
                print("status code not 200; \(response)")
                return
            }
            let json = String(data:data!, encoding: NSISOLatin1StringEncoding)
            let arr: AnyObject? = json?.parseJSONString
            for item in arr as! Array<AnyObject>{
                let newsItem = NewsItem()
                newsItem.dateString = (item["dateString"] as AnyObject? as? String) ?? ""
                newsItem.title = (item["title"] as AnyObject? as? String) ?? ""
                newsItem.imgUrl = (item["imgUrl"] as AnyObject? as? String) ?? ""
                newsItem.url = (item["url"] as AnyObject? as? String) ?? ""
                newsItem.message = (item["message"] as AnyObject? as? String) ?? ""
                self.newsItems.append(newsItem)
            }
            print("Network request finished - call reloadData()")
            dispatch_async(dispatch_get_main_queue(), {
               self.tableView.reloadData()
            })
        }
        task.resume()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        automaticallyAdjustsScrollViewInsets = false
    }

    private func prepareTableView() {
        tableView = UITableView()
        tableView.dataSource = self
        tableView.delegate = self
        tableView.separatorColor = UIColor.clearColor()
    }
}

extension NewsTableViewController : UITableViewDataSource{

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("Item count: ", newsItems.count)
        return newsItems.count
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        print("cellForRowAtIndexPath called with indexPathRow: ", indexPath.row)
        let cell = tableView.dequeueReusableCellWithIdentifier("ImageCardViewCell") as! NewsImageCardViewCell
        let item: NewsItem = newsItems[indexPath.row]
        getImageCardView(item.url, btnDate: item.dateString, textTitle: item.title, textDetail: item.message, imageCardView: cell.imageCardView, imageName: "news_1", indexPath: indexPath)
        return cell
    }
}

extension NewsTableViewController : UITableViewDelegate{
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
    }
}

如您所见:UITableView 已通过将 dataSourcedelegate 设置为我的类而正确设置。 reloadData() 方法在主线程上被调用。按照日志输出:

Item count:  1
cellForRowAtIndexPath called with indexPathRow:  0
Network request finished - call reloadData()
Item count:  72

注意:一开始我的数组中有一个虚拟项只是为了向您展示 cellForRowAtIndexPath 确实被调用了,但只调用了一次。在 numberOfRowsInSection 上触发 reloadData() 后,将调用但不调用 cellForRowAtIndexPath 方法。

我知道有很多类似的问题,我已经检查了所有可能的解决方案,但没有一个有效。感谢您的帮助。

编辑

请注意,在网络请求之前添加的虚拟 View 是可见的。所以 UITableView 的高度不为 0。

编辑#2

感谢大家的回答。我发现了问题。我已经通过 Storyboard 实例化了 ViewController,但我没有设置 IBOutlet。由于我的 UITableView 的边界是 0,0,0,0。

最佳答案

那是因为你的 table view 没有添加到你的 window,如果 table view 不可见,UIKit 将不会处理 UI 相关的方法。这是一种 Apple 的延迟加载
如下更改您的 prepareTableView 函数:

private func prepareTableView() {
    tableView = UITableView(frame: self.view.bounds, style: .Plain)
    tableView.dataSource = self
    tableView.delegate = self
    tableView.separatorColor = UIColor.clearColor()
    self.view.addSubview(tableView)
}

关于ios - reloadData 之后未调用 cellForRowAtIndexPath 但 numberOfRowsInSection 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38763559/

相关文章:

ios - UITableViewCell 内的自定义配件 View 不可见

ios - 如何在代码中获取我的 iOS 项目的当前版本?

ios - 修复文本的最小比例因子

ios - UIRefreshControl 在弹出窗口中不适用于 UITableView

ios - 将字典映射到 ios 中的 TableView ?

ios - 如何使用文件管理器将 iCloud 中的文件复制到应用程序沙箱

ios - 从 iOS 上的 Firebase 数据库事件 childChanged 返回的快照

ios - CoreBluetooth - 具有有意义的 UUID 的 CBMutableCharacteristic 或 CBMutableService

ios - productsRequest 不适用于应用内购买

ios - 如何制作 float /3D Touch 风格的桌面 View ?