user3420815 user3420815 - 4 months ago 27
Swift Question

cellForRowAtIndexPath not called after reloadData but numberOfRowsInSection does

In my current project I'm trying to fetch news from a REST-Endpoint and I wanna refresh the

UITableView
once the network request is finished. So I call
reloadData()
but unfortunately
cellForRowAtIndexPath
isn't called however
numberOfRowsInSection
gets called and returns the correct number of items.

Following my code stripped down to the relevant parts:

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)
}
}


As you can see: The
UITableView
is correctly setup by setting the
dataSource
and
delegate
to my class. The
reloadData()
method is called on the main thread. Following the log-output:

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


Note: At first there's one dummy item my array just to show you that
cellForRowAtIndexPath
is indeed called but only one time. After triggering
reloadData()
on
numberOfRowsInSection
is called but not the cellForRowAtIndexPath method.

I know that there're a lot of similar issues like this and I've checked them all for possible solutions but none were working. I appreciate any help.

Edit



Please note that the dummy view which is added before the network request is visible. So the
UITableView
s' height is not 0.

Edit #2



Thanks to everyone for your answers. I've found the issue. I've instantiated the
ViewController
via the
Storyboard
but I missed to set an
IBOutlet
. Due that the bounds of my
UITableView
were 0,0,0,0.

Answer

That because your table view did not add to your window, If the table view is not visible, the UIKit will not deal with UI related methods. It's kind of Apple's lazy load.
Change your prepareTableView function as below:

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)
}