Home > front end >  Swift: Update Layout and Content of ViewController when dismissing presented ViewController
Swift: Update Layout and Content of ViewController when dismissing presented ViewController

Time:04-01

I have a UIView which displays some information such as a user's Name and more, including a list of objects that all get pulled from my database. This works fine.

However, I now have a ViewController that gets presented on top of the current ViewController. In this presented ViewController, I am adding Data to my Database. When dismissing that view, I want the original ViewController to update all of its content to be up to date.

Right now, all my views are getting layedout in ViewDidLoad, meaning that they only really get loaded once and don't reload later on. I have managed to update Layout by calling self.view.layoutIfNeeded(), but if I understand correctly, this only updates constraint. Of course, I could call a new init of my original view controller. This would make it reload, but I would like to avoid that.

Another Idea I had was to set up all my content in the ViewWillAppear, which should maybe then update anytime my view controller is about to be visible. However, I don't know how to go about doing this. Can I just move all my setup code to viewWillAppear? Does this have any disadvantages?

TLDR: Is there a way to update a stackview with new elements without having to reload the full ViewController over ViewWillAppear?

CodePudding user response:

The UITableView element works very smoothly with database data. If you fetch the data from your database inside viewDidLoad in your first view controller, and store it in an array, the UITableView (if you set up its dataSource correctly) will automatically populate the table with the new values from the second view controller. With this method, there is no need to use ViewWillAppear at all.

It sounds like as of now, you're using Views (inside a VStack)? to display individual objects from the database. If you want to keep whatever custom style/layout you're using with your views, this can be done by defining a custom subclass of UITableViewCell and selecting the "Also create XIB file" option. The XIB file lets you customize how the cells in your UITableView look.

Here is a simple example to show the database values in the first view controller automatically updating. I didn't include the custom XIB file (these are all default UITableViewCells), to keep it streamlined.

FIRST VIEW CONTROLLER

import UIKit
import CoreData

class ViewController: UIViewController {
    @IBOutlet weak var dataTable: UITableView!
    
    var tableRows: [DataItem] = []
    
    func loadData() {
        let request: NSFetchRequest<DataItem> = DataItem.fetchRequest()
        do {
            tableRows = try Global_Context.fetch(request)
        } catch {
            print("Error loading data: \(error)")
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dataTable.dataSource = self
        loadData()
    }


    @IBAction func goForward(_ sender: UIButton) {
        self.performSegue(withIdentifier: "toSecond", sender: self)
    }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableRows.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "dataTableCell", for: indexPath)
        cell.textLabel?.text = tableRows[indexPath.row].name
        return cell
    }
}

let Global_Context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveContext () {
    if Global_Context.hasChanges {
        do {
            try Global_Context.save()
        } catch {
            let nserror = error as NSError
            print("Error saving database context: \(nserror), \(nserror.userInfo)")
        }
    }
}

SECOND VIEW CONTROLLER:

import UIKit
import CoreData

class AddViewController: UIViewController {
    @IBOutlet weak var itemEntry: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        itemEntry.delegate = self
    }
    
    @IBAction func addNewItem(_ sender: UIButton) {
        let newDataItem = DataItem(context: Global_Context)
        newDataItem.name = itemEntry.text
        saveContext()
    }
    
    @IBAction func goBack(_ sender: UIButton) {
        self.performSegue(withIdentifier: "toFirst", sender: self)
    }
}

extension AddViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.endEditing(true)
        return true
    }
}

Main.storyboard: enter image description here

Once you set up your view controller as a UITableViewDataSource (as in the example code), the table view should make things simpler by eliminating any need to manually manage individual Views.

Is this the functionality you were looking for? (Note about the example: it was set up in Xcode with "Use Core Data" enabled.)

Here is a link to the official documentation: https://developer.apple.com/documentation/uikit/uitableview

  • Related