Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
427 views
in Technique[技术] by (71.8m points)

ios - Is prepareForSegue right way of passing value between view controllers

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...