UITableView 中的数据在特定情况下不会刷新

Posted

技术标签:

【中文标题】UITableView 中的数据在特定情况下不会刷新【英文标题】:Data in UITableView doesn't refresh in a specific case 【发布时间】:2017-07-22 11:54:01 【问题描述】:

看起来很奇怪,因为我的 tableView 中的数据大部分都被刷新了,但在特定但确实非常重要的情况下,它不会被刷新。

所以,我有 2 个结构:

struct ItemsStructure 
    var itemId: Int
    var code: String
    var externalId: Int
    var manufactureName: String
    var price: Double
    var weight: Int

以及包含第一个的结构:

struct ListStructure 
    var listId: Int
    var createdDate: Date
    var wasSent: Bool
    var items: [ItemsStructure]

我还有 2 个UITableViewControllers。第一个显示 ListStructure 数组,第二个显示特定选定列表的内容。此外,第二个控制器允许删除列表中的项目。问题是我有一个包含 3 个项目的列表。当我从列表中删除第一个和第二个项目并返回到第一个控制器时,我可能会看到结果:列表包含更少的项目。但是,删除最后一个项目看起来不同。返回到第一个 tableView,我仍然看到 List 包含一个 Item,而它是空的。只有关闭和重新打开应用程序才会显示空列表(没有任何项目)。

是的,我读过关于将 tableView.reloadData() 放入 DispatchQueue.main.async 的内容,但结果与我在没有 DispatchQueue 的情况下调用 tableView.reloadData() 的结果相同。

对列表中项目的任何操作都是通过委托执行的。列表的打印显示列表确实是空的。

下面是 ListViewController 的代码

class ListsViewController: UIViewController 
    var dataSource: ListViewDataSource!

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() 
        super.viewDidLoad()
        tableView.estimatedRowHeight = tableView.rowHeight
        tableView.rowHeight = UITableViewAutomaticDimension
    

    override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(animated)
        tableView.dataSource = dataSource
        DispatchQueue.main.async 
            self.tableView.reloadData()
        
    

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == "ShowParticularItem" 
            if let listVC = segue.destination as? ParticularListViewController 
                let listNumberToPass = tableView.indexPathForSelectedRow!.row
                let listToPass = dataSource.stateController.lists[listNumberToPass]
                listVC.listNumber = listNumberToPass
                listVC.list = listToPass
                listVC.delegate = dataSource.self
            
        
    


protocol ParticularListViewControllerDelegate: class 
func delete(listNumber: Int, itemNumber: Int)

class ParticularListViewController: UITableViewController 
var listNumber: Int!
var list: ListStructure!
weak var delegate: ParticularListViewControllerDelegate?


@IBOutlet weak var creationTimeLabel: UILabel!
@IBOutlet weak var sentStatusLabel: UILabel!
@IBOutlet weak var weightLabel: UILabel!
@IBOutlet weak var totalCostLabel: UILabel!
@IBOutlet weak var sentListButtonOutlet: UIButton!
@IBAction func sentListButton(_ sender: UIButton) 
    sentList()
    markListAsSent()
    refreshData()


func refreshData()
    self.creationTimeLabel.text = "The list was created at \(list.createdDate)"
    if list.wasSent 
        self.sentStatusLabel.text = "The list has been already sent"
        self.sentListButtonOutlet.isEnabled = false
     else 
        self.sentStatusLabel.text = "The list hasn't been sent yet"
        self.sentListButtonOutlet.isEnabled = true
    
    let totalWeight: Int = list.items.reduce(0, $0 + $1.weight)
    self.weightLabel.text = "The list contains \(list.items.count) items with total weight \(totalWeight) gramms"
    self.totalCostLabel.text = "The total cost is: \(list.totalCost) ₽"
    tableView.reloadData()


override func viewDidLoad() 
    super.viewDidLoad()
    refreshData()


override func viewWillAppear(_ animated: Bool) 
    super.viewWillAppear(animated)
    refreshData()


override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return list.items.count


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ParticularListTableViewCell
    let index = indexPath.row
    cell.item = list.items[index]

    return cell


func delete(itemNumber: Int)
    delegate?.delete(listNumber: listNumber, itemNumber: itemNumber)
    self.refreshData()

extension ListViewDataSource: ParticularListViewControllerDelegate 
func delete(listNumber: Int, itemNumber: Int) 
    stateController.delete(fromList: listNumber, itemNumber: itemNumber)

class ListViewDataSource: NSObject
var stateController: StateController

init(stateController: StateController) 
    self.stateController = stateController

extension ListViewDataSource: UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    return stateController.lists.count


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "ListsCell", for: indexPath) as! ListsTableViewCell
    let index = indexPath.row
    let listToPass = stateController.lists[index]
    cell.listToShow = ListsTableViewCell.ListModel(model: listToPass)

    return cell

class StateController
fileprivate let storageController: StorageController
fileprivate(set) var lists: [ListStructure]
fileprivate let context: NSManagedObjectContext

init(storageController: StorageController, context: NSManagedObjectContext) 
    self.storageController = storageController
    self.context = context
    self.lists = storageController.fetchAllLists(inContext: context)

正如我在 ListViewController.ViewWillAppear 中打印之前所说的那样,stateController.lists.Items 是空的

【问题讨论】:

显示要删除的代码;请记住,结构体和数组是 Swift 中的值类型 请编辑您的问题以包含附加代码。在 cmets 中阅读非常困难 【参考方案1】:

由于 Array 和 Structs 是值类型,因此您对副本所做的更改不会得到反映。更新数据源后,确保更新源视图控制器的数据源。您可能需要为此实现委托。其他方法是通过单例拥有公共数据源,但我不建议这样做。

【讨论】:

嗨!谢谢你,很抱歉回复晚了。 ListsViewController 的 dataSourse 是 ListsViewDataSource.listsArray,它正在通过 extention ListViewDataSource: ParticularListViewControllerDelegate 中的委托函数 delete 进行更新。 我明白你纠正了数组值类型的问题吗?由于 UITableView 正在刷新,直到内部数组不为空。只有当内部数组为空时,UITableView 才会停止刷新。 全部同意。您的 tableView.dataSoure = dataSource 而不是 self.即 ListsViewController。在数据源中的 numberOfRows 处放置一个断点。在那里你可能会意识到你返回的数字仍然是 1。请检查一下。 刚刚检查过。不:有 0 个项目。 homber.ru/i/emptyItems.png 你为讨论中的tableView实现了numberOfRows吗?在此处设置一个断点并检查您正在重新调整的内容。

以上是关于UITableView 中的数据在特定情况下不会刷新的主要内容,如果未能解决你的问题,请参考以下文章

UItableView滚动到特定位置

Swift UIRefresh Control 在 UITableView 中拖动刷新会导致应用崩溃

仅在单元格中的特定 UIImage 上从 UITableView 推送详细信息视图?

如何将特定 NSMutableArray 中的数据重新加载到 UITableView

嵌入在 UIStackView 中的 UITableView 不会重新加载数据

如何在 UITableView 中设置 UILabel 的动作