【问题标题】:Refreshing Child Controllers with Segmented Control使用分段控制刷新子控制器
【发布时间】:2021-04-18 21:52:00
【问题描述】:

我的父视图控制器包含两个容器视图和一个在两个视图之间切换的分段控件。每个 Container View 显示一个 tableView。这两个子视图控制器分别称为printingView 和completedView。

用户可以将项目标记为完成,并将其从printingView tableView 中删除并显示在completedView tableView 上。我遇到的问题是在 segmentedControl 切换以显示该视图时刷新 completedView tableView。到目前为止,当从 printView 中删除项目时,我需要导航到另一个页面并返回 PrintJobs ViewController 才能看到项目出现在 completedView 中。

在实施时,这两个视图被隐藏并适当地显示。由于视图在页面上仍然处于活动状态,因此在切换分段控制器时,子 tableView 不会更新。如何实现子表视图,以便在调用 segmentedControl 时重新加载?

父 VC

class PrintJobsVC: UIViewController {

    @IBOutlet weak var printingView: UIView!
    @IBOutlet weak var completedView: UIView!

    var printer:PrinterDisplay? // passed from the VC before via segue

    @IBAction func toggleSegmentedController(_ sender: UISegmentedControl) {
        switch sender.selectedSegmentIndex {
        case 0:
            // PrintingView
            setView(view: printingView, hidden: false)
            setView(view: completedView, hidden: true)

        case 1:
            // CompletedView
            setView(view: printingView, hidden: true)
            setView(view: completedView, hidden: false)

        default:
            print("hit default case of toggleSegmentedController")
            setView(view: printingView, hidden: false)
            setView(view: completedView, hidden: true)
        }
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "PrintingSegue", let nextVC = segue.destination as? IndividualPrintingVC {
            print("individualPrinting segue")
            nextVC.printer = printer
        } else if segue.identifier == "CompletedSegue", let nextVC = segue.destination as? IndividualCompletedVC {
            print("completedSegue")
            nextVC.printer = printer
        }
    }

    func setView(view: UIView, hidden: Bool) {
        UIView.transition(with: view, duration: 0.3, options: .transitionCrossDissolve, animations: {
            view.isHidden = hidden
        })
    }

}

Child PrintingVC(CompletedVC 布局相同)

class PrintingVC: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    var printer:PrinterDisplay?
    var printingArray:[PrintingDisplay] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self
        tableView.dataSource = self
        getCoreData() // retrieves from core data and stores in printingArray
    }
    
    override func viewWillAppear(_ animated: Bool) {
        DispatchQueue.main.async { self.tableView.reloadData() }
    }
}

// tableview methods
extension PrintingVC: UITableViewDelegate, UITableViewDataSource {
    // set up how many rows are in the tableview
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return printingArray.count
    }
    
    // sets up a cell in the tableview
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PrintingCell", for: indexPath as IndexPath) as! PrintingTableViewCell
        
        let item = printingArray[indexPath.row]
        // setup cell parameters

        return cell
    }
}

// mark the item as complete, remove from printingArray, modify Core Data
extension PrintingVC: PrintingTableViewCellDelegate {
    func markCompleted(row: Int, indexPath: IndexPath) {
        let item = printingArray[row]
        // confirm that the user wants to complete print
        let alert = UIAlertController(title: "Are you sure?", message: "\(item.item) will be marked as completed. It can be found in the printer's individual page", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: {action in
            self.markCompletedCoreData(uid: item.uid)
            self.printingArray.remove(at: row)
            self.tableView.deleteRows(at: [indexPath], with: .fade)
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        self.present(alert, animated: true)
    }
}

【问题讨论】:

  • 看这个问题/答案:stackoverflow.com/a/48892520/6257435
  • @DonMag 我查看了帖子并尝试在调用 segue 时存储对子 VC 的引用。在 segmentedController 中,我在主线程中调用了它们各自的 tableView.reloadData() 但仍然面临同样的问题。切换分段控制器时,tableview 没有更新。
  • 我假设您的每个子 VC 都是表视图控制器?您如何管理他们的数据?您正在使用“数据管理器”类吗?当用户在printingView 表中标记一个项目“已完成”时,您是否将其从printingView 控制器的数据中删除并将其添加到completedView 控制器数据中?然后在completedView 控制器上调用.reloadData
  • 子 VC 是 UIContainerViews,其中嵌入了一个 tableView。它们都有各自的包含表格视图和数组的类(PrintingVC、CompletedVC)。因此,当在 PrintingVC 中标记项目时,它会从打印数组 tableview 中删除,并且它的布尔完成属性在核心数据中更新。由于 CompletedVC 在视图加载后从核心数据中提取,因此在刷新之前,此项不会出现在 CompletedVC 数组和 tableview 上(父视图重新加载,从核心数据中提取新的数据)。我已经为子 VC 添加了代码 sn-ps。

标签: ios swift uitableview uicontainerview


【解决方案1】:

有多种方法可以做到这一点......


使用您当前的方法,对于您的每个子 VC,您正在将 viewDidLoad() 中的核心数据中的数据加载到一个数组中。然后,您可以使用该数组来填充表格。

当您在 PrintingVC 中标记“已完成”项时,您会更新 Core Data,从数组中删除元素,并从表中删除行。

问题是,这不会更新CompletedVC 中的数组。

因此,您需要让PrintingVC 告诉PrintJobsVC 记录已更改(使用闭包或协议/委托模式),然后PrintJobsVC 会告诉CompletedVC 更新它的 数组并重新加载它的表。

这种方法相当“蛮力”,但会奏效。


更好的方法是使用 Fetched Results Controller 和 Managed Object Context 来观察 Core Data 的变化并自动更新/刷新表格视图。 p>

你需要做一些研究(那里有很多教程)来学习如何做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    • 2013-03-31
    • 2015-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多