为啥我的函数没有重新加载 UITableView 的数据?

Posted

技术标签:

【中文标题】为啥我的函数没有重新加载 UITableView 的数据?【英文标题】:Why isn't my function reloading the UITableView's data?为什么我的函数没有重新加载 UITableView 的数据? 【发布时间】:2020-10-10 09:24:13 【问题描述】:

我正在创建一个表格视图,用于监控来自几个帐户的前 20 条推文并按时间顺序显示它们。它调用 Twitter API,然后遍历推文并将它们添加到 tableview。我的问题是,当我尝试刷新 tableview 中的数据时,什么也没有发生。我尝试再次调用 getTwitterInfo() ,但即使有新的推文要显示,它也不会做任何事情。我已经尝试了所有可以在网上找到的方法,但似乎没有任何解决方法。任何帮助将不胜感激——这是我的视图控制器的代码。

class TwitterViewController: UIViewController 

    var tableView = UITableView()

    var tweets = [Tweet]()

    let cellID = "cellID"

    var accounts: [String:String] = [
        //this is just a dictionary of the accounts I'm monitoring and their corresponding profile picture
    ]

    override func viewDidLoad() 
        super.viewDidLoad()
        navigationController?.setNavigationBarHidden(true, animated: false)

        configureTableView()
        getTwitterInfo()
    

    func configureTableView()
        view.addSubview(tableView)
        tableView.delegate = self
        tableView.dataSource = self

        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 150

        tableView.register(TweetCell.self, forCellReuseIdentifier: cellID)

        tableView.translatesAutoresizingMaskIntoConstraints = false
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true


    

    func getTwitterInfo()

        print("getting new info...")


        tweets = [Tweet]()

        var counter = 1

        for (name, pfpLink) in accounts
            let imageURL = URL(string:pfpLink)!

            var image = UIImage()

            let imageDataTask = URLSession.shared.dataTask(with: imageURL)  (data,response,error) in
                image = UIImage(data:data!)!
            

            imageDataTask.resume()


            let url = URL(string: "https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=\(name)&count=20&tweet_mode=extended")!

            var request = URLRequest(url: url)
            request.allHTTPHeaderFields = ["Authorization": Constants.bearer]

            let dataTask = URLSession.shared.dataTask(with: request) (data,response,error) in
                do
                    let data = try JSONSerialization.jsonObject(with: data!, options: []) as? [[String:Any]]

                    let _ = data!.map
                        let htmlEncodedString = $0["full_text"] as! String

                        let message: String
                        if let newDict = $0["retweeted_status"] as? Dictionary<String,Any>
                            let newEncodedString = newDict["full_text"] as! String
                            message = Constants.decodeTwitterString(newEncodedString)
                        else
                            message = Constants.decodeTwitterString(htmlEncodedString)
                        

                        let userInfo = $0["user"] as! Dictionary<String,Any>

                        let screenName = userInfo["screen_name"] as! String
                        let username = userInfo["name"] as! String

                        let twitterID = userInfo["id_str"] as! String

                        let dateString = $0["created_at"] as! String

                        let tweet = Tweet(name: username, username: screenName, message: message, twitterID: twitterID, image:image, dateString: dateString)
                        self.tweets.append(tweet)
                    

                    if (counter == self.accounts.keys.count) 
                            let formatter = DateFormatter()
                            formatter.dateFormat = "EE LLL dd HH:mm:ss Z yyyy"

                            self.tweets = self.tweets.sorted
                                formatter.date(from: $0.dateString)! > formatter.date(from: $1.dateString)!
                            
                        DispatchQueue.main.async
                            self.tableView.reloadData()
                        

                    

                    counter += 1

                catch let err
                    print(err)
                
            

            dataTask.resume()

        
    


extension TwitterViewController: UITableViewDelegate, UITableViewDataSource 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return tweets.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TweetCell
        let tweet = tweets[indexPath.row]

        cell.set(tweet:tweet)
        cell.selectionStyle = .none

        return cell
    



【问题讨论】:

【参考方案1】:

我假设你已经验证了 try 没有抛出异常,并且强制 unwrap 没有崩溃。我认为你应该做的是移动

DispatchQueue.main.async
    self.tableView.reloadData()

到它所在的 if 块的外部和之后。我怀疑 tableView.reloadData() 没有被调用,因为它所在的 if 块中的条件检查失败。试试看,让我知道它是否对您有帮助。如果没有,您最好从 GitHub 向我发送指向您项目的链接。

如果您不想向后兼容运行 ios 13 更低版本的设备,请使用 Google UITableViewDiffableDataSource。用新方法来做这件事要容易得多,特别是当项目变得有点复杂时,需要管理许多 tableview 状态更改,从而为您省去很多麻烦。如果您想查看它,这是一个很好的起点:[https://developer.apple.com/videos/play/wwdc2019/220/][1]

【讨论】:

我只是在该块内放了一个打印语句,它确实最终打印了 - 似乎一切都在运行,但由于某种原因它无法正常工作。 我刚刚发现似乎是问题所在。我从另一个视图控制器调用 getTwitterInfo(),我想当我调用它时我必须把它放在它自己的 Dispatch.main.async 块中。我真的不明白为什么,但是嘿,它有效。无论如何感谢您的帮助! 跟进:我还必须以编程方式创建 TwitterVIewController 的实例,而不是通过情节提要实例化它。超级奇怪——我不确定这会如何改变任何事情,但它只能这样工作。

以上是关于为啥我的函数没有重新加载 UITableView 的数据?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftyJSON 没有重新加载 UITableView

无法重新加载 UITableView

防止uitableView重新加载

为啥我的 UIView 在重新加载后没有响应?

为啥我的 UITableView 单元格上的这个按钮会重新绘制自己?

UITableview 没有重新加载