0

I can think of four ways that my code allows ViewControllers to interact:

1. If I am calling a new VC onto the stack, I pass it the data it needs in the prepare for segue, like so:

Prepare for segue - passing data

2. Unwind segues help me when I am going in reverse and heading back to a VC.

3. I can use protocols to call a function in one VC from another VC.

4. I also have a VC I named "ToolBox" and I sometimes reference "Toolbox" functions by doing something like:

var toolBox = ToolBox()
toolBox.fetchReq_taskList_Sorted(currentListEntity)

Initializing my new VC by passing values, like in #1, I think I understand. Using #2, unwind segues, to run a function on unwind but not pass data, I think I understand.

Question

Where I start to get confused is #3 versus #4. They both let me delegate to another class/VC. Why bother with a protocol when #4 is simpler? Just to ensure that the delegate conforms?

And what about when I don't need to delegate the handling of an event? What about when I just need to be passing a variable's value around? That could also be handled by:

  • Saving the cell temporarily to CoreData, the recalling it from other VCs
  • Or doing that with NSUserDefaults
  • Or I could use a Global Variable to remember the cell

On forums, I always see people saying don't use NSUserDefaults for this, don't use Global variables unless "x", etc. So is there a specific, correct decision making tree for all this?

Dave G
  • 12,042
  • 7
  • 57
  • 83
  • As I mentioned in the answer to your related question. Don't pass the cell, pass the object with which the cell is being configured. The original vc holding that object will see all of the changes that are made to it without any additional code. – danh Nov 30 '15 at 18:03
  • If you need me to elaborate, please post your `cellForRowAtIndexPath` code. It will almost certainly contain the single line of code you need to move forward. – danh Nov 30 '15 at 18:05
  • Very important distinction: `protocols` are just "templates", what you are describing is `delegation`, which is a design pattern that uses a `protocol` type. Just like a `Singleton` is a pattern that uses a `class` type. Google delegation for tons of good info. – R Menke Nov 30 '15 at 19:36
  • 1
    As for your question: The general rule is : Use delegation. when you think you can't use delegation, still use delegation. If your navigation is so complex that delegation becomes impossible, change the navigation. – R Menke Nov 30 '15 at 19:39
  • Another way, Dave, but not a pretty way if you are new to this. Create a custom UITableViewCell. Attach an block handler to the cell. Attach a UIGestureRecognizer to the cell inside the custom cell. Then, in your CellForRowAtIndexPath .. you first weakify and then strongfy the "cell parameter" the sen this to the block method and then call to the block method in your ViewController. I do this all the time, and it's far eaiser for me to set this up than to deal with protocols and delegation. – Larry Pickles Nov 30 '15 at 20:56
  • Please post code, not screenshots of code. Not everyone views SO in a way that makes viewing screenshots easy. – rickster Nov 30 '15 at 21:04
  • @danh The other posted question I posted yesterday I now understand. However, I'm still trying to clarify the method differences above. I reworded this question to be clearer. Would you mind taking a look? – Dave G Dec 01 '15 at 09:15

1 Answers1

1

VCs are responsible for parts of the model. They react to user actions by changing the model, and they observe changes in the model to update their views. They communicate with each other indirectly, because they both observe the same shared model.

To recap my answer to your other question, when vcA which presents an array of model objects in a tableview wants to tell vcB on which specific object to operate, it can do so directly by assigning that object to a vcB property which is vcB's part of the model....

    vcA                  vcB
     |                    /
   vcA's model       vcB's model (assigned to it before a segue)
     |                  /
   ----------------    /
   |       |       |  /
 obj0     obj1     obj2


 Before presenting vcB, vcA assigns it part of the model (obj2, in this example).

See how there's no need to "pass back" anything from vcB to vcA? They're both looking at the same thing. While true, this leaves unanswered some questions implied by your post...

vcA probably needs to know if vcB changes the model so it can update its views. Doesn't vcB need to tell vcA about that?

This is a big topic, but the short answer is that vcA can observe the model changing using KVO and notification.

What about delegation? Is that a way for vcs to coordinate?

Yes. Notification is sometimes a little too broadcast-y and KVO is sometimes a little too narrow and verbose. With delegation, vcB says to its delegate: "I'll do my job of changing my part of the model, and you should do whatever it is you do when I do what I do".

This highly rated post on the subject of inter-vc communication does a good job explaining how to implement delegation.

Delegation is a little over-prescribed, imo. I prefer to use it for richer interactions (the way NSURLConnectionDelegate or UITableViewDatasource works), but using it between vcs to communicate about model changes is common practice that works.

How about the "target-action" pattern?

You didn't mention this one, but its another pattern, delegation's hackier cousin. Outside of custom UIControl subclasses, I'd stay away.

What about global variables? Are they bad?

Yes.

A more subtle answer allows for a commonly used few, including a singleton root of your model. But in general, you should avoid globals for the same reason you don't use wooden clubs: for most (non-bludgeoning-related) jobs, they do more harm than good.

What about my ToolBox class or CoreData or NSUserDefaults?

Your ToolBox class might really be part of your model, maybe you just haven't realized it or named it that way. CoreData for persistence of the model between app launches. Not really pertinent here. NSUserDefaults is persistence of user prefs between launches, also not pertinent.

Using these instead of the patterns sanctioned above is like using global variables, except a little worse, because they are often applied as global variables, only renamed to obscure the ill-advised approach.

Community
  • 1
  • 1
danh
  • 62,181
  • 10
  • 95
  • 136
  • THANK YOU for the in-depth answer. It helped quite a bit. Your comment about my ToolBox being part of the model, I hadn't realize it until now but I think that's dead-on. I'm obviously just beginning to grasp how object-oriented programming models should be designed. I'm sure it will be a while before I build my apps in any way that is close to optimal. I'll try to make this my last question: Besides trial & error plus YouTube videos, is there any resource for learning best-practices that is better than the rest? Some kind of amazing online course or iOS app, etc? – Dave G Dec 01 '15 at 23:35
  • Glad it was helpful. About learning sources - I think the best learning comes from job experience with good colleagues. If that's not available, you can get some free theoretical background via something like Stanford on iTunesU, and practical help from WWDC content, this site, something like Ray Wenderlich, and so on. Whatever you do, definitely, definitely, learn by trying and failing. Don't set out for optimal, go for working, then edit and edit and edit to improve. – danh Dec 02 '15 at 03:12
  • "Don't set out for optimal, go for working, then edit and edit and edit to improve." That is wind in my sails (-: Already watching some Stanford videos and WWDC stuff, I'll watch more. Good to know I was on the right track. Living abroad now but maybe I'll land a job at an app company when I get back! Doubt anyone would hire me as a developer at this point. – Dave G Dec 02 '15 at 17:30