简体   繁体   English

UITableView tableView.reloadData()调用时没有更新,请问是什么原因导致的?

[英]UITableView not updating when tableView.reloadData() is called, what is causing this problem?

I have a table view that initially starts empty.我有一个最初为空的表视图。 I am trying to update it once an asynchronous method is called Networking().fetchRecipies(ingredients: searchText) .一旦异步方法被调用Networking().fetchRecipies(ingredients: searchText) ,我就会尝试更新它。 However, after this method is called, the recipieTableView remains unpopulated.但是,调用此方法后, recipieTableView仍未填充。 What is causeing this error?是什么导致了这个错误? Below is the code I am running that should be run everytime the text in the text field changes.下面是我正在运行的代码,每次文本字段中的文本更改时都应运行该代码。 I know this is working because I am also printing the results of the API call我知道这是有效的,因为我也在打印 API 调用的结果

@IBOutlet weak var recipieTableView: UITableView!
var recipies = LocalData.recipies.recipieList
var filteredRecipies = [Recipie]()
    
    
override func viewDidLoad() {
    filteredRecipies = recipies
    super.viewDidLoad()
}

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
     Networking().fetchRecipies(ingredients: searchText)
     self.recipieTableView.reloadData()
     DispatchQueue.main.async {
         self.recipieTableView.reloadData()
         self.recipieTableView.beginUpdates()
         self.recipieTableView.endUpdates()
     }
}

However, after this method is called, the recipieTableView remains unpopulated.但是,调用此方法后,recipieTableView 仍未填充。 What is causeing this error是什么导致了这个错误

What's causing the error is that when you say "after" you should actually be saying "before".导致错误的原因是,当您说“之后”时,您实际上应该说“之前”。 Your code does not run in the order it is written: It runs in this order:您的代码不按编写的顺序运行:它按以下顺序运行:

 Networking().fetchRecipies(ingredients: searchText) // 2
 self.recipieTableView.reloadData() // 1...
 // ...

In other words, all your calls to reloadData are happening before you fetch the recipes.换句话说,您对reloadData的所有调用都发生您获取食谱之前。

You need to write fetchRecipes such that it reloads the table view after the fetching has finished.您需要编写fetchRecipes以便在获取完成后重新加载表视图。

You say the method Networking().fetchRecipies(ingredients:) is called asynchronously, which basically means your code steps into another thread and simultaneously continues to execute to the end of the method your asynchronous function was called from.你说方法Networking().fetchRecipies(ingredients:)被异步调用,这基本上意味着你的代码进入另一个线程并同时继续执行到你的异步 function 被调用的方法结束。

So the line self.recipieTableView.reloadData() is called when your data is not yet populated.因此,当您的数据尚未填充时,将调用self.recipieTableView.reloadData()行。

After that you call DispatchQueue.main.async which is also unnecessary.之后你调用DispatchQueue.main.async这也是不必要的。 Since you're already on the main thread (because that's the convention for searchBar(_:textDidChange:) , as for the most of UIKit methods), the only thing your method does is runs the contents of the dispatched block of code some time later (but chances are still much sooner before your fetch request completes).由于您已经在主线程上(因为这是searchBar(_:textDidChange:)的约定,对于大多数 UIKit 方法),您的方法唯一要做的就是在某个时间运行分派的代码块的内容稍后(但在您的获取请求完成之前,机会仍然要早得多)。

Read more on how concurrency works on iOS in the official guide .在官方指南中阅读更多关于并发如何在 iOS 上工作的信息。 If you're a beginner, it would be just enough to understand the difference between serial and concurrent queues and sync and async dispatches.如果您是初学者,了解串行和并发队列以及syncasync调度之间的区别就足够了。

Back to your problem.回到你的问题。 I suggest that you examine the API of your Networking class and check if there's any way to notify you when your data has been actually fetched.我建议您检查Networking class 的 API 并检查是否有任何方法可以在实际获取数据时通知您。 Most iOS APIs provide a completion block that is executed with your newly fetched data passed as an argument.大多数 iOS API 都提供一个完成块,该块使用作为参数传递的新获取的数据执行。 For example, it could look like the following:例如,它可能如下所示:

Networking().fetchRecipies(ingredients: searchText, completion: { fetchedIngredients in 
   // ... update your data source array
   // reload table view
})

Call tableView.updateData() directly from inside such a block if it's called on the main queue, or wrap it inside DispatchQueue.main.async { } if your completion block is invoked from a background queue (refer to the API to find it out).如果在主队列上调用tableView.updateData()直接从这样的块内部调用,或者如果您的完成块是从后台队列调用的,则将其包装在DispatchQueue.main.async { }中(请参阅 API 找到它).

And, most important, don't forget to update your array (I believe it's either recipies or filteredRecipies ) which serves as the source for your table's data BEFORE you call updateData() .而且,最重要的是,不要忘记在调用updateData()之前更新您的数组(我相信它是recipiesfilteredRecipies )作为表数据的来源。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM