Home > database >  iOS UITableView Not Showing
iOS UITableView Not Showing

Time:11-22

I'm kinda new to iOS, was working on network fetching from the GitHub API but not able to show the users in the table view. Below is the code,

View Controller:

    import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var avatarImage: UIImageView!
    @IBOutlet weak var userName: UILabel!
    @IBOutlet weak var usersTableView: UITableView!

    var network = Network()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        network.delegate = self
        usersTableView.dataSource = self
    }

    override func viewWillAppear(_ animated: Bool) {
        network.network()
    }
}

extension ViewController: NetworkDelegate {
    func updateTableView() {
        DispatchQueue.main.async {
            self.usersTableView.reloadData()
        }
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let users = network.users {
            print(users.count)
            return users.count
        } else {
            return 0
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("CALLED")
        let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! UserViewCell
        return cell
    }
}

btw, the identifier is from the .xib file, the identifier matches, I don't think the problem is occurring here.

Network File

import Foundation

protocol NetworkDelegate {
    func updateTableView()
}

class Network {
    var users: [GitHub]?
    var delegate: NetworkDelegate?

    func network() {
        let url = "https://api.github.com/users"
        let request: URLRequest?

        if let URL = URL(string: url) {
            request = URLRequest(url: URL)
            URLSession.shared.dataTask(with: request!) { result, response, error in
                if let data = result {
    //                print(String(data: data, encoding: .utf8)!)

                    self.users = self.parseJSON(data)
                    self.delegate?.updateTableView()
                } else {
                    print(error!.localizedDescription)
                }
            }
            .resume()
        }
    }

    private func parseJSON(_ data: Data) -> [GitHub]? {
        let json = JSONDecoder()
        do {
            let decodedData = try json.decode([GitHub].self, from: data)
//            print(decodedData)
            return decodedData
        } catch {
            print(error.localizedDescription)
        }
        return nil
    }
}

The GitHub API Model

struct GitHub: Codable {
    let login: String
    let id: Int
    let node_id: String
    let avatar_url: String
    let gravatar_id: String
    let url: String
    let html_url: String
    let followers_url: String
    let following_url: String
    let gists_url: String
    let starred_url: String
    let subscriptions_url: String
    let organizations_url: String
    let repos_url: String
    let events_url: String
    let received_events_url: String
    let type: String
    let site_admin: Bool
}

When I run this code on the simulator, the output is blank (Below the label)

enter image description here

Not able to figure out where I'm doing wrong

Thanks In Advance.

CodePudding user response:

Try to refactor you code using a completion handler without using the delegation pattern.

in your network file:

enum ApiError: Error {
    case network(Error)
    case genericError
    case httpResponseError
    case invalidData
    case decoding
    // you can handle your specific case 
}


  func network(completion: @escaping ( _ error: ApiError?, _ users: [GitHub]?)-> Void) {
        let url = "https://api.github.com/users"
        let request: URLRequest?
        
        if let URL = URL(string: url) {
            request = URLRequest(url: URL)
            URLSession.shared.dataTask(with: request!) { result, response, error in
                if let error = error {
                    completion(.network(error), nil)
                    return
                }
                guard let httpResponse = response as? HTTPURLResponse,
                      (200...299).contains(httpResponse.statusCode) else {
                          completion( .httpResponseError, nil)
                          return
                      }
                guard let data = result else {
                    completion(.invalidData, nil)
                    return
                }
                do {
                    let decodedData = try JSONDecoder().decode([GitHub].self, from: data)
                    completion(nil, decodedData)
                } catch {
                    completion(.decoding, nil)
                }
            }
            .resume()
        }
    }

then inside your ViewController you can use it this way:

   override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        network.network { [weak self] error, users in
            guard let self = self else { return }
            if let error = error {
                print(error)
                return
            }
            DispatchQueue.main.async {
                guard let users = users else { return }
                self.users = users
                self.tableView.reloadData()
            }
        }
    }

if it still doesn't show and cellForRow doesn't get called, you probably have a problem with your constraints and the tableView frame is zero (either height, width or both).

Try to debug setting a breakpoint inside numberOfRowsInSection and then in your debug area po tableView or just print the tableView and check if width or height is zero. it will be probably get called a few times. The first time the frame should be zero but at some point you should get a frame with height and width. If don't then check your constraints.

You can check my example which has a table view 375 x 641

enter image description here

CodePudding user response:

If your cell is a xib file then you have to register your cell with tableView.

before calling datasource in viewDidLoad

override func viewDidLoad() {
    super.viewDidLoad()
        // Do any additional setup after loading the view.
    usersTableView(UINib(nibName: "userCell", bundle: nil), forCellReuseIdentifier: "userCell")
    network.delegate = self
    usersTableView.dataSource = self
    }
  • Related