在 reloadData 后不调用 cellForRowAtIndexPath 但 numberOfRowsInSection 调用

use*_*815 4 uitableview ios swift

在我当前的项目中,我试图从 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见:UITableView通过将dataSource和设置delegate为我的班级来正确设置。该reloadData()方法在主线程上调用。按照日志输出:

Item count:  1
cellForRowAtIndexPath called with indexPathRow:  0
Network request finished - call reloadData()
Item count:  72
Run Code Online (Sandbox Code Playgroud)

注意:首先我的数组中有一个虚拟项目只是为了向您展示它cellForRowAtIndexPath确实被调用了但只有一次。触发reloadData()numberOfRowsInSection被称作但不是的cellForRowAtIndexPath方法。

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

编辑

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

编辑 #2

感谢大家的回答。我找到了问题所在。我已经实例化了ViewControllervia,Storyboard但我错过了设置IBOutlet. 由于我的界限UITableView是 0,0,0,0。

Pra*_*iya 6

检查以下:

1numberOfRowsInSection看返回值的数量

2 如果调用 step1 并返回正确的值仍然没有调用cellForRowAtIndexPath,这意味着您的表格视图高度小于单元格高度或表格视图高度为 0 ,打印表格视图边界并检查表格视图的超级视图是否有剪辑边界为 TRUE


zyl*_*env 6

那是因为你的 table view 没有添加到你的窗口,如果 table view 不可见,UIKit 不会处理 UI 相关的方法。有点像苹果的lazy load
更改您的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)
}
Run Code Online (Sandbox Code Playgroud)

  • @ user3420815 我认为 zylenv 的答案是正确的,因为您没有将 tableview 添加到 self.view 中,那么您怎么可能看到您的 table view。你在 storyBorad 或 Nib 中有 UITableviewObject 所以它的显示吗? (2认同)