代码之家  ›  专栏  ›  技术社区  ›  Gustavo Picciuto

仅在JSON之后加载tableView

  •  0
  • Gustavo Picciuto  · 技术社区  · 6 年前

    我意识到tableView.reloadData重新加载数据()在JSON完成块中调用get,用接收到的数据重新加载tableView;我想知道是否有办法只在完成块之后加载tableView。所发生的情况是,tableView首先加载带有默认单元格的空值,几秒钟后在完成块内调用reloadData()方法,tableView重新加载,数据与自定义单元格一起出现。我只想在收到数据后加载tableView。我可以采取什么方法?是否有办法仅在完成后加载视图?我基本上不想让用户在空白表上看几秒钟,然后等待数据出现。下面是我的viewController代码和简单的结构,用于保存数据的模型。

    视图控制器:

        import UIKit
    
    class ViewController: UIViewController, UITableViewDataSource {
    
        var users = [User]()
        @IBOutlet weak var tableView: UITableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
    
            guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { return }
            URLSession.shared.dataTask(with: url) { (data, response, error) in
                do {
                    guard let data = data else { return }
                    let recieved = try JSONDecoder().decode([User].self, from: data)
                    self.users = recieved
                    DispatchQueue.main.async {
                        self.tableView.reloadData()
                    }
                } catch let error as NSError {
                    print("Error: \(error.description)")
                }
            }.resume()
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return users.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
            cell.name.text = users[indexPath.row].name
            cell.eMail.text = users[indexPath.row].email
            return cell
        }
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
    }
    

    结构:

        struct User: Decodable {
    
        let id: Int
        let name: String
        let username: String
        let email: String
        let company: Company
    
    }
    
        struct Company: Decodable {
    
        let name: String
        let catchPhrase: String
        let bs: String
    
    }
    
    3 回复  |  直到 6 年前
        1
  •  0
  •   Phil    6 年前

    既然您基本上是在等待网络调用,然后才能显示数据,为什么不在tableview顶部的视图上显示微调器或活动指示器,然后在成功解析数据(或处理任何错误)后取消此操作呢。另一种方法是在视图加载到另一个类之前请求数据。

        2
  •  0
  •   Hendra Halim    6 年前

    我认为您可以在UITableView中添加活动指示器。所以用户不会只看到空白的UITableView。或者可以在UITableView中添加背景图像,如果数据仍然为空,则可以显示背景图像,并在JSON解码后将其隐藏。

    对于UITableView中的参考背景图像,您可以看到 here

        3
  •  0
  •   Gustavo Picciuto    6 年前

    根据你的建议,这是我使用活动指示器的路线。我在tableView的前面设置了一个UIView,然后在该UIView的上面添加了一个activityIndicator,并在activityIndicator旁边添加了一个简单的UILabel,字符串为“Loading”。在接收到数据并重新加载tableView之后,我在JSON任务中使用了propertyAnimator,然后停止activityIndicator,淡出UIView以显示tableView,然后从superView中删除UIView。代码如下:

    import UIKit
    
    

    class ViewController: UIViewController, UITableViewDataSource {

    var users = [User]() @IBOutlet weak var tableView: UITableView! @IBOutlet weak var loadingView: UIView! @IBOutlet weak var activityIndicator: UIActivityIndicatorView! override func viewDidLoad() { super.viewDidLoad() guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { return } URLSession.shared.dataTask(with: url) { (data, response, error) in do { guard let data = data else { return } let recievedUsers = try JSONDecoder().decode([User].self, from: data) self.users = recievedUsers DispatchQueue.main.async { self.tableView.reloadData() if self.loadingView.alpha == 1.0 { self.activityIndicator.stopAnimating() UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1.0, delay: 0.0, options: [], animations: { self.loadingView.alpha = 0.0 }, completion: { (position) in if position == .end { self.loadingView.removeFromSuperview() } }) } } } catch let error as NSError { print("Error: \(error.description)") } }.resume() } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return users.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell cell.name.text = users[indexPath.row].name cell.eMail.text = users[indexPath.row].email return cell } func numberOfSections(in tableView: UITableView) -> Int { return 1 }

    }