Ajil O. Ajil O. - 9 months ago 36
Swift Question

Passing values from a custom view to Main View Controller - Swift

I am working on a basic alarm app. This is how the main storyboard looks like

enter image description here

I have added a custom view controller as a separate xib file which looks like this

enter image description here
enter image description here

And this is how the interface looks like when it runs. (The main ViewController in background and the CustomAlertController in the foreground)

enter image description here

It contains a date picker. What I mean to do is that when a user clicks on the addButton in the Main story board the customAlertViewController will come up and the user can choose a date and time to add as an alarm. When the user taps on Add in the customAlertViewController the date and time are supposed to be passed back into an array and added to the tableView in the Main storyboard view controller.

This is the code I have written so far:

Code for TableView

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let adate = alarmDate[indexPath.row].date
cell.textLabel?.text = String(adate)
return cell

Code in the Alarm class

import Foundation
class Alarm{
var date : NSDate
init (date : NSDate){
self.date = date

Code in CustomAlertViewController

You don't have to go through the entire code. I have tried using prepare for segue, but I guess that's not a doable solution when the CustomAlertviewcontroller is in a different storyboard(?)

The next approach I took was to somehow pass the date to an instance of Alarm class in the viewDidDisappear method, and subsequently append it to alarmDate array (declared in ViewController).

This is where I am getting stuck. The print statement in the viewDidDisappear outputs 1 to the console, obviously because the date has been appended. But once the CustomAlertViewController exits and the viewController is back, the alarmDate array resets and no value shows up in the table view. I have tried to work around this but to no avail.

I realise that if I had used a new view controller in the storyboard in place of a separate xib file, I could have achieved the same result easily.

class CustomAlertViewController: UIViewController {
//MARK: - Properties
@IBOutlet weak var customAlertView: UIView!
@IBOutlet weak var alarmPicker: UIDatePicker!
var destinationDate = NSDate()
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName : nibNameOrNil, bundle : nibBundleOrNil)
self.modalPresentationStyle = .OverCurrentContext
convenience init(){
self.init(nibName : "CustomAlertViewController", bundle: nil)
required init?(coder aDecoder: NSCoder) {
fatalError("NSCoding not supported")

//MARK: - Methods
override func viewDidLoad() {
print ("View loaded")
self.customAlertView.layer.borderColor = UIColor.darkGrayColor().CGColor
self.customAlertView.layer.borderWidth = 2
self.customAlertView.layer.cornerRadius = 8
view.backgroundColor = UIColor(white: 1, alpha: 0.7)
view.opaque = false
override func didReceiveMemoryWarning() {
override func viewDidDisappear(animated: Bool) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("table") as! ViewController
let alarm = Alarm( date : destinationDate)
// vc.alarmData.reloadData()
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as! ViewController
let alarm = Alarm( date : destinationDate)
//MARK: - Actions
@IBAction func cancelButton(sender: AnyObject) {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
@IBAction func addButton(sender: AnyObject) {
//Code to correct the time zone difference
let sourceDate = alarmPicker.date
let sourceTmeZone = NSTimeZone(abbreviation: "GMT")
let destinationTimeZone = NSTimeZone.systemTimeZone()
let sourceOffset = sourceTmeZone!.secondsFromGMTForDate(sourceDate)
let destinationOffset = destinationTimeZone.secondsFromGMTForDate(sourceDate)
let interval : Double
interval = Double(destinationOffset - sourceOffset)
destinationDate = NSDate.init(timeInterval: interval, sinceDate: sourceDate)

self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)

I lack experience with Swift and would gladly appreciate any help.
PS I'm using Swift 2.3

Answer Source

You could use a protocol:

protocol DateShare {
    func share(date: NSDate)

which you declare wherever you want outside of any controller scope. then you add a

delegate: DateShare!

property in your CustomAlertVC. In the VC, when you init the CustomAlert, you add this line:

customAlert.delegate = self

And of course you add an extension that you conform to the DateShare protocol in your VC, as so:

extension ViewController: DateShare {
    func share(date: NSDate) {
         // do whatever you can for that the date can be displayed in table view 
        alarmDates.append(date) // if I understood it all ?

And finally you add this line in addButton(sender: _) scope:

@IBOutlet func addButton(sender: UIButton?) {
    // generate inputDate here
    delegate.share(date: inputDate)

This should make the trick.