Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is prepareForSegue right way of passing value between view controllers

Tags:

ios

swift

segue

I'm trying to learn Swift and I'm trying to develop the famous note application.

There is an array bound to a tableview and another view for adding notes. At second view textfieldshouldreturn event triggers a segue and goes back to tableview.

I wanted to learn if this is the right way. Because by doing this way I'm manipulating a variable in another view controller. I'm not a MVC master but I felt like it is wrong. Here is my code snippet:

func textFieldShouldReturn(textField: UITextField) -> Bool {

    self.performSegueWithIdentifier("backSegue", sender: self)
    return true
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if(segue.identifier == "backSegue"){
        let navController = segue.destinationViewController as UINavigationController;
        let myController = navController.topViewController as NotesTableViewController;
        if(self.ourTextField?.text != nil || self.ourTextField?.text != ""){
            myController.notes.append(self.ourTextField?.text ?? "");
        }

    }
}

Thank you.

like image 336
Mehmet Kemal Bayer Avatar asked Dec 13 '14 08:12

Mehmet Kemal Bayer


1 Answers

Your question is not really about prepareForSegue but the relationship between view controllers. The reason that your design "feels wrong" is that it is. The problem is that your note writing view controller knows too much about the view controller that is using it because it is directly manipulating a variable from the calling view controller. In order to directly manipulate the variable, it must know the class of the caller.

Why is this a problem? It makes your note writing view controller less reusable. If you write the note writing view controller correctly, then you could reuse it in other apps. To make it reusable, you need to decouple the note writing view controller from the caller - it must not know who exactly is calling it.

So the question becomes, how do I pass data back to the caller if I don't know who called me? The answer is delegation.

Delegation works like this:

  1. You create a protocol which describes a method or methods that the implementor of that protocol will implement. In your case, you could use a protocol like NoteWriterDelegate that implements the method takeNote(note: String).

    protocol NoteWriterDelegate {
        func takeNote(note: String)
    }
    

    Define this in the file along with your note writing view controller.

  2. Your note writer will have an optional pointer to the delegate:

    weak var delegate: NoteWriterDelegate?
    
  3. You need to declare your first view controller as a NoteWriterDelegate:

    class ViewController: UITableViewController, NoteWriterDelegate
    
  4. And then implement the required method in your first view controller:

    func takeNote(note: String) {
        notes.append(note)
    }
    
  5. When you call prepareForSegue in preparation for moving to the note writing view controller, you pass yourself as the delegate:

    destinationViewController.delegate = self
    
  6. In the note writing view controller, when you have a note to pass back to the caller, you call takeNote on the delegate:

    delegate?.takeNote(self.ourTextField?.text ?? "")
    

By doing it this way, your note writer only knows that it is talking to a NoteWriterDelegate. If you want to reuse this in the future, you just drop your note writer class into another project, implement the delegate, and it works without you having to touch the code in the note writer class.

like image 124
vacawama Avatar answered Oct 14 '22 07:10

vacawama