Swift - 关闭模态视图控制器后重新加载表视图

4
我正在将一个视图控制器显示为父视图控制器上的弹出窗口。
在 ModalVC 的解除 dismiss 中,将数据传递给一个函数,在该函数中使用新数据重新加载 ParentVC 中的 TableView。
我尝试过以下方法:
1. 在 ModalVC 的 dismiss 语句前调用 'reloadData' 函数 2. 使用 dismiss 完成处理程序 3. 使用通知中心 4. 单例模式-调用 reload-TableView 函数 5. 解除处理程序
但每次都会出现错误。
self.myTableView.reloadData()

顺便提一下,'myTableView' 是一个带有有效连接的 @IBOutlet

错误信息:

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

我可以确认,我能够在控制台打印发送到表格单元的数据。

我还检查了当关闭ModalVC时,ViewWillAppear/ViewDidAppear不会加载,感谢Sean确认

我需要在关闭ModalVC/Popup时重新加载ParentVC中的TableView。

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()

} 

}

}

能否添加您的表视图和ModalVC的代码?谢谢。 - Andres Gomez
你在哪里调用了 self.myTableView.reloadData() - Mojtaba Hosseini
@AndresGomez 我已添加代码 - uzair
@MojtabaHosseini,那个语句'reloadData()'在ParentVC.swift文件中,是最后的第四行。我刚刚编辑了问题并添加了代码,如果您能参考一下就太好了。 - uzair
3个回答

3

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)


}    

}

2

以下是错误信息:

let logbookObj = LogbookViewController()

你正在创建一个新的实例,而不是从Storyboard中加载你的视图控制器(这就是为什么tableView为空),你可以通过以下方式访问它:
    // 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)
    }
})

1
作为建议,避免强制解包。 - Francesco Deliro
是的,“value”是可选的,我需要强制对它进行解包。 - uzair
啊,好的,所以呈现的视图控制器为空或不是LogbookViewController。我会编辑我的答案。 - Francesco Deliro
它将前一个视图控制器传递给了ParentVC,但在“self.logBookTableView.reloadData()”处出现了相同的错误。致命错误:在隐式解包可选值时意外发现nil 2019-11-30 [36467:1346045] 致命错误:在隐式解包可选值时意外发现nil。再次说明,视图 - ViewDidLoad / ViewWillAppear / ViewDidAppear未执行。 - uzair
@uzair,当前的视图控制器是一个UINavigationController,现在请尝试,我的答案已更新。 - Francesco Deliro
显示剩余2条评论

2
在 ModelVC 中创建协议委托。
protocal RefreshDataDelegate() {
  func refreshData()
}

创建委托变量
var viewDelegate: RefreshDataDelegate?

使用这个代理来重新加载数据,你可以在关闭ModalVC时调用这个方法。

viewDelegate.refreshData()

在父视图控制器(parentVC)中,当你展示模态视图控制器(ModalVC)时,请添加这行代码。
let vc = your modalvc 
 vc.viewDelegate = self

若要添加委托,请添加以下代码行:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接