3

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
    print(adate)
    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() {
        super.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() {
        super.didReceiveMemoryWarning()
    }
    override func viewDidDisappear(animated: Bool) {
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("table") as! ViewController
        let alarm = Alarm( date : destinationDate)
        vc.alarmDate.append(alarm)
//        vc.alarmData.reloadData()
        print(vc.alarmDate.count)
    }
    // MARK: - Navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        let destinationVC = segue.destinationViewController as! ViewController
        let alarm = Alarm( date : destinationDate)
        destinationVC.alarmDate.append(alarm)
        destinationVC.alarmData.reloadData()
        print(destinationVC.alarmDate.count)
    }
    //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

Ajil O.
  • 6,562
  • 5
  • 40
  • 72
  • 1
    The best way to accomplish this is by using a protocol and delegate to pass information between the view controllers. I would learn about protocols and delegation regardless because they're value concepts to know as you get better. There's plenty of resources both online and through stackoverflow on this. Here is one tutorial to get you started: http://www.iphonelife.com/blog/31369/swift-programming-101-mastering-protocols-and-delegates-part-2 – user3353890 Nov 04 '16 at 07:59
  • Thanks!. I'll look that up – Ajil O. Nov 04 '16 at 08:05
  • 1
    You're welcome! I'd post code, but there are so many resources already out there that it would be redundant at this point. If you have a specific question though, I'd be happy to help! Also, you can probably accomplish this with notification center, but it's more of a "hacky" way. You could run into issues down the line with notification center for something like this. Protocols are the "proper" way I guess you could say. OR if you're using a navigation controller, you can use an "unwindSegue" function to accomplish the same thing. Good luck! – user3353890 Nov 04 '16 at 08:28
  • @user3353890 Thanks! Finally figured out how to work with protocols. The tutorial was a great help – Ajil O. Nov 07 '16 at 03:43
  • You're welcome! I'm glad it helped. – user3353890 Nov 07 '16 at 20:56
  • Well notification is not a good process. You can do this by protocols. – User511 Nov 04 '16 at 11:35

1 Answers1

3

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.

Stormsyders
  • 285
  • 2
  • 11
  • No problem, if you want further explanations I can provide some to you :) – Stormsyders Nov 04 '16 at 12:51
  • I just tried your code, but couldn't get it to work. I didn't understand how to get `customAlert.delegtae = self` to compile. What did you mean to do here? By customAlert did you mean the CustomAlertViewController? Where do I have to type the code? – Ajil O. Nov 07 '16 at 02:28
  • Never mind. I have figured it out and made the necessary edits. Thanks for your help! – Ajil O. Nov 07 '16 at 03:42