Swift - Reload TableView After Dismissing Modal ViewController

reload uiviewcontroller programmatically swift
swift dismiss previous view controller
reload tableview from another viewcontroller swift
dismiss modal view controller and present another
dismiss modal view controller and present another swift
dismiss view controller swift
viewwillappear not called after dismiss modal
update uitableview without reloaddata

I'm showing a View Controller as a Popup on a Parent ViewController(VC).

On Dismiss of ModalVC, data from ModalVC is passed to a function that reloads TableView in ParentVC with fresh data.

Things I've tried

  1. Calling 'reloadData' function before dismiss-statement from ModalVC
  2. Dismiss Completion handler
  3. Notification Center
  4. Singleton - To call reload-TableView function
  5. Dismiss Handler

Each time I get an error for this statement.

self.myTableView.reloadData()

FYI, 'myTableView' is an @IBOutlet with a valid connection

The Error Message:

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
2019-11-30 02:40:30[31116:1071948] Fatal error: Unexpectedly found nil while implicitly 
unwrapping an Optional value

I can confirm that I'm able to print data in the console that is being sent to Table Cell

I've also checked that on dismissing ModalVC, the ViewWillAppear/ViewDidAppear doesn't load and thanks to Sean for confirming it.

I need help reloading TableView in ParentVC on dismissing ModalVC/Popup.

ModalVC.swift

import UIKit
import ACFloatingTextfield_Swift
import Alamofire
import SwiftyJSON

class UISearchViewController: UIViewController,UITextViewDelegate,UITextFieldDelegate {

@IBOutlet weak var searhView: UIView!
@IBOutlet weak var patientUMRIpNo: ACFloatingTextfield!
@IBOutlet weak var fromDateTF: UITextField!
@IBOutlet weak var toDateTF: UITextField!
@IBOutlet weak var submitButtonOutlet: UIButton!


let logBookRef:LogbookViewController = LogbookViewController()
let datePickerView = UIDatePicker()
let datePicker = UIDatePicker()

let searchVC = "SearchPatient"

var rawSearchData : JSON!

var patientSearchDetails:[String:Any] = [:]

var patientNameArr:[String] = []
var patientAgeArr: [String] = []
var patientGenderArr:[String] = []
var patientUmrIdsArr:[String] = []
var patientMobileNoArr:[String] = []
var patientDatesArr:[String] = []

override func viewDidLoad() {
    super.viewDidLoad()

    submitButtonOutlet.layer.borderColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
    submitButtonOutlet.layer.cornerRadius = 10
    submitButtonOutlet.layer.masksToBounds = true
    patientUMRIpNo.delegate = self
    fromDateTF.delegate = self
    toDateTF.delegate = self

    searhView.layer.cornerRadius = 10
    searhView.layer.masksToBounds = true


    textFieldPlaceHolder()

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard(_sender:)))
    self.view.addGestureRecognizer(tapGesture)



}
@objc func dismissKeyboard(_sender:UITapGestureRecognizer){
    patientUMRIpNo.resignFirstResponder()
    fromDateTF.resignFirstResponder()
    toDateTF.resignFirstResponder()


}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    if (touch!.view != self.searhView) {
            self.dismiss(animated: true, completion: nil)
        }
}

// TextField placeholder method
func textFieldPlaceHolder(){
    placeHolderWhite(textFieldName: fromDateTF, placeHolderText: "Select from date")
    placeHolderWhite(textFieldName: toDateTF, placeHolderText: "Select to date")
}

func placeHolderWhite(textFieldName:UITextField, placeHolderText:String){
    textFieldName.attributedPlaceholder = NSAttributedString(string: placeHolderText ,attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])

}


func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    fromDateTF.inputView = datePickerView
    toDateTF.inputView = datePicker
    datePickerView.datePickerMode = .date
    datePicker.datePickerMode = .date

    let toolBar = UIToolbar().ToolbarPiker(mySelect: #selector(UISearchViewController.dismissPicker))
    fromDateTF.inputAccessoryView = toolBar
    toDateTF.inputAccessoryView = toolBar

    datePickerView.addTarget(self, action: #selector(handleDatePicker(sender:)), for: .valueChanged)
    datePicker.addTarget(self, action: #selector(handleDatePickerTwo(sender:)), for: .valueChanged)

    return true
}
@objc func dismissPicker() {
     view.endEditing(true)
    }
@objc func handleDatePicker(sender: UIDatePicker) {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd-MM-yyyy"
    fromDateTF.text = dateFormatter.string(from: sender.date)

}
@objc func handleDatePickerTwo(sender: UIDatePicker){
           let formatDate = DateFormatter()
            formatDate.dateFormat = "dd-MM-yyyy"
            toDateTF.text = formatDate.string(from: sender.date)
}
func getPatientData(_ completion: @escaping (JSON?) -> Void){

    let parameters:[String:Any] = [KeyConstants.mobileNo:self.getUserMobileNumberFromUserDefaults(),
        KeyConstants.keyword:self.patientUMRIpNo.text ?? "" ,
        KeyConstants.datedvalue:self.fromDateTF.text ?? "",
        KeyConstants.todatedValue: self.toDateTF.text ?? ""]

    print(parameters)
    Alamofire.request(AppUrl.searchPatientUrl, method: .post, parameters: parameters).responseJSON { (response) in
        if response.result.isSuccess{

            let patientSearchJSON : JSON = JSON(response.result.value!)
            // print(patientSearchJSON)
            print("Raw Search Results......\(patientSearchJSON)")

            if patientSearchJSON["status"] == "3"{
             completion(patientSearchJSON)
                //self.bindSearchedData(json: patientSearchJSON)

            }

}
    }}

func bindSearchedData(json:JSON){
    for i in 0..<json["status_messsage"].count{
        let patientNames = json["status_messsage"][i]["patient_name"].stringValue
        let patientUmrNos = json["status_messsage"][i]["patient_umr_ipno"].stringValue
        let patientGenderNames = json["status_messsage"][i]["patient_gender"].stringValue
        let patientMobileNos = json["status_messsage"][i]["patient_mobile"].stringValue
        let patientDateValues = json["status_messsage"][i]["patient_date"].stringValue
        let patiendAgeValues = json["statue_message"][i]["patient_age"].stringValue


        patientNameArr.append(patientNames)
        patientUmrIdsArr.append(patientUmrNos)
        patientGenderArr.append(patientGenderNames)
        patientMobileNoArr.append(patientMobileNos)
        patientDatesArr.append(patientDateValues)
        patientAgeArr.append(patiendAgeValues)

    }



}


@IBAction func submitButtonAction(_ sender: Any) {
    showToast(message: "Submit func calling", font: UIFont.systemFont(ofSize: 15))
    getPatientData() { value in


        // Modal/Popup - DISMISS
        self.dismiss(animated: true, completion: {

            let logbookObj = LogbookViewController()

            logbookObj.updatePatientSearch22(json: value!)


        })


}    
}
}

ParentVC.swift

import UIKit
import FSCalendar
import Alamofire
import SwiftyJSON
import ACFloatingTextfield_Swift

class LogbookViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, FSCalendarDataSource, FSCalendarDelegate,FSCalendarDelegateAppearance,LogbookCellDelegate{
@IBOutlet weak var calendar: FSCalendar!
@IBOutlet weak var headerTitle: UILabel!
@IBOutlet weak var calendarHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var logBookTableView: UITableView!
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var logBookTableViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var overViewHeightConstraint: NSLayoutConstraint!

var patientUrl = [String]()


fileprivate var lunar: Bool = false {
    didSet {
        self.calendar.reloadData()
    }
}

fileprivate let formatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "MMMM yyyy"

    return formatter
}()

fileprivate lazy var dateFormatter: DateFormatter = {
    let formatter = DateFormatter()
   formatter.dateFormat = "yyyy-MM-dd"

    return formatter
}()

fileprivate let gregorian: NSCalendar! = NSCalendar(calendarIdentifier:NSCalendar.Identifier.gregorian)

fileprivate let gregorianmove:NSCalendar =  NSCalendar(calendarIdentifier:NSCalendar.Identifier.gregorian)!

var datedValue = ""


var patientNamesList:[String] = []
var patientName = PatientSearchDataModel()

var patientAgeList: [String] = []
var patientAge = PatientSearchDataModel()

var patientGenderList:[String] = []
var patientGender = PatientSearchDataModel()

var patientUmrIdsList:[String] = []
var patientUmrId = PatientSearchDataModel()

var patientMobileNoList:[String] = []
var patientMobileNo = PatientSearchDataModel()

var patientCategoryDiagnosysList:[String] = []
var patientCategoryDiagnosys = PatientSearchDataModel()

var patientHospitalNameList:[String] = []
var hospitalName = PatientSearchDataModel()

var patientRefDoctorNameList:[String] = []
var patientRefDocName = PatientSearchDataModel()

var patientRefDoctorMobileNoList:[String] = []
var patientRefDocMobileNo = PatientSearchDataModel()

var patientOperationDoneList:[String] = []
var patientOperationDone = PatientSearchDataModel()

var patientDatesList:[String] = []
var patientDate = PatientSearchDataModel()

var dateValue = CalendarLogDataModel()
var dateValuesList:[String] = []

var logBookMonth = ""
var logBookYear = ""

//Declaring the variables for disply search options
var patientType:String?
var searchPatientIP:String?
var searchPatientFromDate:String?
var searchPatientToDate:String?

override func viewDidLoad() {
    super.viewDidLoad()
    self.calendar.appearance.headerMinimumDissolvedAlpha = 0.0
    self.logBookTableView.isHidden = true
    self.logBookTableView.separatorStyle = .none
    self.logBookTableView.reloadData()
    self.scrollView.bounces = false
    if UIDevice.current.model.hasPrefix("iPad") {
        self.calendarHeightConstraint.constant = 400

    }

    self.calendar.appearance.caseOptions = [.headerUsesUpperCase,.weekdayUsesUpperCase]

   //self.calendar.select(self.formatter.date(from: "2017/08/10")!)

    let scopeGesture = UIPanGestureRecognizer(target: self.calendar, action: #selector(self.calendar.handleScopeGesture(_:)))
    self.calendar.addGestureRecognizer(scopeGesture)

    // For UITest
    self.calendar.accessibilityIdentifier = "calendar"
    self.curentDate()

}

override func viewWillAppear(_ animated: Bool) {
    callCalenderApi()
    self.calendar.reloadData()

    //calendar.appearance.eventColor = UIColor.greenColor
    self.logBookTableView.reloadData()

}

override func viewDidAppear(_ animated: Bool) {
    self.logBookTableView.reloadData()

}

@IBAction func rightArrowButton(_ sender: Any) {
    calendar.setCurrentPage(getNextMonth(date: calendar.currentPage), animated: true)
}

@IBAction func leftArrowButton(_ sender: Any) {
   calendar.setCurrentPage(getPreviousMonth(date: calendar.currentPage), animated: true)
}

func getNextMonth(date:Date)->Date {
    self.logBookTableView.isHidden = true
    return  Calendar.current.date(byAdding: .month, value: 1, to:date)!
}
func getPreviousMonth(date:Date)->Date {
     self.logBookTableView.isHidden = true
    return  Calendar.current.date(byAdding: .month, value: -1, to:date)!
}   

@IBAction func backButton(_ sender: Any) {
    let dashBoard = self.storyboard?.instantiateViewController(withIdentifier: "HomeVC") as? HomeViewController
    self.navigationController?.pushViewController(dashBoard!, animated: true)

}

@IBAction func searchButton(_ sender: Any) {
    let searchPatientVC = self.storyboard?.instantiateViewController(withIdentifier:"SearchVC") as? UISearchViewController
    searchPatientVC!.modalTransitionStyle   = .crossDissolve
    searchPatientVC!.modalPresentationStyle = .overCurrentContext

    self.present(searchPatientVC!, animated: true, completion: nil)

}



func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return patientDatesList.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = logBookTableView.dequeueReusableCell(withIdentifier: "LogbookTVC", for: indexPath) as? LogbookTableViewCell
    cell?.delegate = self

    cell?.selectionStyle = .none

    cell?.patientNameLabel.text = patientNamesList[indexPath.row]
    cell?.patientIpNumberLabel.text = patientUmrIdsList[indexPath.row]
    cell?.patientGenderLabel.text = patientGenderList[indexPath.row]
    cell?.patientMobileNumberLabel.text = patientMobileNoList[indexPath.row]
    cell?.patientDateLabel.text = patientDatesList[indexPath.row]


    cell?.shareButtOL.tag = indexPath.row
    cell?.messageButtOL.tag = indexPath.row
    cell?.deleteButtOL.tag = indexPath.row
    cell?.printButtOL.tag = indexPath.row
    cell?.viewButtOL.tag = indexPath.row
    return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 200
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let cell = logBookTableView.dequeueReusableCell(withIdentifier: "LogbookTVC") as? LogbookTableViewCell
    logBookTableViewHeightConstraint.constant = logBookTableView.contentSize.height
    overViewHeightConstraint.constant = logBookTableView.contentSize.height + CGFloat(340)
    cell?.contentView.backgroundColor = UIColor(red: 59, green: 87, blue: 157, alpha: 1.0)
}



func updatePatientSearch22(json: JSON){




        self.patientNamesList = []
        self.patientUmrIdsList = []
        self.patientGenderList = []
        self.patientMobileNoList = []
        self.patientDatesList = []
        self.patientAgeList = []


        for i in 0..<json["status_messsage"].count{

            let patientNamee = json["status_messsage"][i]["patient_name"].stringValue
            let patientUmrNumber = json["status_messsage"][i]["patient_umr_ipno"].stringValue
            let patientGenderName = json["status_messsage"][i]["patient_gender"].stringValue
            let patientMobileNumber = json["status_messsage"][i]["patient_mobile"].stringValue
            let patientDateValue = json["status_messsage"][i]["patient_date"].stringValue
            let patiendAgeValue = json["statue_message"][i]["patient_age"].stringValue


            self.patientName.patientname = patientNamee
            self.patientUmrId.patientumripno = patientUmrNumber
            self.patientGender.patientgender = patientGenderName
            self.patientMobileNo.patientmobile = patientMobileNumber
            self.patientDate.patientdate = patientDateValue
            self.patientAge.patientage = patiendAgeValue


            self.patientNamesList.append(patientNamee)
            self.patientUmrIdsList.append(patientUmrNumber)
            self.patientGenderList.append(patientGenderName)
            self.patientMobileNoList.append(patientMobileNumber)
            self.patientDatesList.append(patientDateValue)
            self.patientAgeList.append(patiendAgeValue)


        }

        print("Patient Name List", self.patientNamesList)
        print(self.patientUmrIdsList)
        print(self.patientGenderList)
        print(self.patientMobileNoList)
        print(self.patientDatesList)

    // ERROR-POINT
     self.logBookTableView.reloadData()

} 

}

}

ParentVC.swift

@IBAction func searchButton(_ sender: Any) {
    let searchPatientVC = self.storyboard?.instantiateViewController(withIdentifier:"SearchVC") as? UISearchViewController
    searchPatientVC!.modalTransitionStyle   = .crossDissolve
    searchPatientVC!.modalPresentationStyle = .overCurrentContext
    searchPatientVC.searchCompletion = {(model,flag) in
   if(flag){
    self.updatePatientSearch22(json:model)
    self.logBookTableView.reloadData()

   }
 }
    self.present(searchPatientVC!, animated: true, completion: nil)

}

ModalVC.swift

typealias completion = (NSArray,Bool)->Void
var searchCompletion:completion!


@IBAction func submitButtonAction(_ sender: Any) {
    showToast(message: "Submit func calling", font: UIFont.systemFont(ofSize: 15))
    getPatientData() { value in

     self.dismiss(animated: true, completion: nil)
    self.searchCompletion(value,true)


}    

}

Swift, ParentVC.swift @IBAction func searchButton(_ sender: Any) { let searchPatientVC = self.storyboard?.instantiateViewController(withIdentifier:" SearchVC") as? However, I was having trouble getting the table to automatically run a tableView.reloadData function upon dismissing the modal view. The answer that worked for me was in the comments above: You likely want to do this using an unwind segue on the modal, that way you can set up a function on the parent that gets called when it unwinds

Here is the error:

let logbookObj = LogbookViewController()

You are creating a new instance and you are not loading your view controller from the storyboard (that’s why the tableView is nil), you can access it in this way:

    // Modal/Popup - DISMISS
self.dismiss(animated: true, completion: {
    if let navigationController = self.presentingViewController as? UINavigationController, 
       let logbookObj = self.navigationController.viewControllers.first as? LogbookViewController, 
       let value = value {
        logbookObj.updatePatientSearch22(json: value)
    }
})

How can you reload a ViewController after dismissing a modally , Swift 5: You can access the presenting ViewController (presentingViewController) property and use it to reload the table view when the view will disappear. When you dismiss the SecondViewController, the tableview of the FirstViewController will reload. Questions: When I dismiss a modal view controller I want the tableview to update, I am using the form sheet presentation style on iPad so the viewWillAppear and the viewDidAppear methods will not work Answers: Swift 3 version code: In your first view controller: override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(loadList), name

Create Protocal delegate in ModelVC

protocal RefreshDataDelegate() {
  func refreshData()
}

create delegate variable

var viewDelegate: RefreshDataDelegate?

use this delegate to reload your data like and you can call this method while dismissing ModalVC

viewDelegate.refreshData()

In parentVC When you show ModalVC add this line

let vc = your modalvc 
 vc.viewDelegate = self

for Delegate add this line

extension ParentVC: RefreshDataDelegate {
func refreshData() {
    // reload or load data here
 }
}

iOS TableView Reload after dismissing modal, iOS TableView Reload after dismissing modal. Question -working; User edits record in a view controller presented as a modal form view. -working; User saves � It's short and easy to use to reload the tableView's data, but every time reloadData is called, the TableView does 2 things: reloads the tableView with the dataSource, and also resets the scroll position to all the way up top. If that does not affect your user experience, then it's fine.

dismiss(animated:completion:), The block to execute after the view controller is dismissed. The top-most view is dismissed using its modal transition style, which may differ from the styles� Because you now have two view controllers in your project, it makes sense to give ViewController.swift a more meaningful name. To rename the ViewController.swift file. In the project navigator, click the ViewController.swift file once and press the Return key. Xcode lets you type in a new name for the file. Rename the file MealViewController

viewWillAppear and modalview, tableView.reloadData()" for the presenting viewController after the presented viewController is dismissed). you can handle more sophisticated cases either by � Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload.

xcode, In Swift, I want to reloadData the parent view tableview at the timing of dismissing xcode - in swift, i want to reloadtable of the parent view at the timing when modal is dismissed UIViewController {; ~ Omitted ~; func refresh () {; if let loginData = self. so you can call refresh () with the following code. For reference, be aware that you might be dismissing the wrong view controller. For example, if you have an alert box or modal showing on top of another modal. (You could have a Twitter post alert showing on top of your current modal alert, for example). In this case, you need to call dismiss twice, or use an unwind segue.

Comments
  • can you add the code of your table view, and the ModalVC? please
  • Where are calling self.myTableView.reloadData()?
  • @AndresGomez I've added code
  • @MojtabaHosseini That statement 'reloadData()' is in ParentVC.swift, last fourth line. I just edited the question with code, It will be great if you can refer it.
  • As a suggestion avoid force unwrap.
  • I tried your code and the compiler doesn't execute this part if let logbookObj = self.presentingViewController as? LogbookViewController let value = value { logbookObj.updatePatientSearch22(json: value!) }
  • I just edited my previous comment. Also, there is no error, it doesn't read that part
  • Yes, 'value' is optional, I need to force unwrap it.
  • Ah ok, so the presenting view controller is nil or is not LogbookViewController. I will edit my answer.