I'd like to know which one approach is better and why. When passing data, do you use the delegation pattern to pass data between VCs or you create the destination VC in the prepareForSegue from the VC that you are making the segue and setting the modified data directly from that vc? I'm currently using the delegation pattern, but many people I see are accessing and setting variables directly in the prepareForSegue method of the destination VC.
There isn't really much difference. Passing through prepareForSegue is a simpler option, but if not done correctly can create bad links in your app.
prepareForSegue only passes information, but delegation calls delegate methods.
Delegation mostly leaves everything for the delegate to do.
Delegate methods can be called at any time, but prepareForSegue, as the name suggests, is only called before the segue.
Basically, they have the same effect, but take different paths to the effect.
Related
I try using a custom segue to configure a destination controller for purposes of passing data and injecting dependency.
Using UIStoryboardSegue for purposes of injecting dependencies and passing data
This way separates a destination controller and configuration code from a source controller.
But Apple's documentation says 'A UIStoryboardSegue object is responsible for performing the visual transition between two view controllers.'
Is my usage the right way?
I suppose there are many ways to solve those problems. A segue is a good way to pass data by calling "prepareForSegue" method. Nevertheless, you don't need it to change data in another controller. If you have some parameters in an instance of a view controller class but not show it, you could just take a reference to it by using something like:
let resultViewController = storyboard?.instantiateViewControllerWithIdentifier("result")
as! ResultViewController
In that code, "result" is the id of a view controller. No segue is required for that. You could just create a callback for an UI element and call this code to get a reference to that view controller. I think this could be a better solution if you don't want to transition views.
Hope this helps,
I'm trying to make a custom view controller for use in my projects, that has possible 3 segues from it. But those are not mandatory.
When view controller loads i'm calling a method "trySegues()" that should try to perform all 3 of those segues. Segues are custom, so each successful call will be handled and registered in my code.
In Objective-C i would do that using "#try - #catch" so all the successful calls will go forward, while if one of those segues is not set, it'll raise an exception, but it will be handled by me manually so it won't break the execution of the program.
Is there a way to do the same in Swift?
Using Optionals to simulate an exception won't work, since the performSegueWithIdentifier function returns no value.
In no imaginable way is #try-#catch-ing a performSegueWithIdentifier: the appropriate approach to this challenge. Not in Objective-C. Not in Swift.
Segues can't (or shouldn't) exist independently of storyboards. After all, if you were try to instantiate a segue, the class name is UIStoryboardSegue. The fact that this class even exists publicly is not so that you can instantiate it and add it at run time. It exists so that you can subclass the segue, choose your subclass on the storyboard, and set up a segue with custom behavior:
In Objective-C and Swift, exceptions are reserved for truly exceptional behavior. Behavior which can be prevented at development time. We should not be relying on #try-#catch blocks during run-time by the time we've released our app. We should have fixed our app so that there's nothing to #catch.
So with this said, the only way that performSegueWithIdentifier: can throw an exception is if the segue identifier we gave it does not exist. The only reason the segue shouldn't exist is because we made a typo somewhere.
The segues are hooked up and defined at compile time. There is no public mechanism for checking whether or not a particular segue exists because we just shouldn't be doing this at all.
Now, with all that said, if we want to dynamically push or modally present a particular view controller at run time, and we can't know at compile time what view controller it will be (or from what view controller we're getting to it from), then we shouldn't be presenting it via a segue.
Instead, we should be using one of the presentation options the UIViewController class defines.
Your options are:
presentViewController(_:animated:completion:)
showViewController(_:sender:)
showDetailViewController(_:sender:)
And in place of an unwind segue, you'd want something like this:
dismissViewControllerAnimated(_:completion:)
I am using the UIViewControllerContainment feature in iOS. My container controller is called mainViewController. It consists of menuViewController and contentViewController. The menuViewController is a UITableViewController.
Now, I want that when I select a row in menuViewController I handle an event inside the mainViewController. I have to do all of this without changing the code of menuViewController.
** I am aware I can use delegates to call the mainViewController but using the delegate will alter ** the menuViewController code which I do not want to do.
Assuming that the menuViewController isn't designed with some sort of delegate or callback block (or you wouldn't be asking the question), you're options are really very limited, and there are no good options, since any option would violate the concept of containment that you're trying to take advantage of.
As I see it, your choices are:
Modify the menuVieController to add a delegate or block callback on item selection. This is the best approach since it keeps the menuViewController well contained and isolated.
Subclass the menuViewController, override didSelectCell... and do number 1. Probably need to make sure you call super as well. This is bad because you're making assumptions about the internal structure of menuViewController and violating containment.
Steal the tableView delegate and handle it yourself. This makes even more assumptions about the internals of menuViewController.
Bottom line, I'd really recommend you rethink the decision not to change menuViewController.
I have two controllers in the storyboard, embedded in a NavigationController, and there is a segue to switch between these.
Passing data from the first controller to the second one is pretty straightforward by implementing prepareForSegue, and set the properties of the second controller using segue.destinationViewController.
I should pass back data to the from the second controller to the previous one also. I googled, but I have not found any simple, but working code to demonstrate it.
Would you be so kind give me a simple sample about the best way to do it?
Thanks in advance!
In your second view controller class you create a protocol and delegate. The first view controller will set it self as the delegate in prepareForSegue and implement the protocol methods. The second view controller will then call the methods to pass data back to the first view controller. Here is some code from one of my projects as an example.
#protocol TableSelectorDelegate <NSObject>
#optional
- (void)didMakeSelection:(id)selectionString forType:(NSString *)dataTitle;
- (void)didAddNewValue:(NSString *)newValue forType:(NSString *)dataTitle;
#end
#interface TableSelectorViewController : UITableViewController
#property (nonatomic, weak) id<TableSelectorDelegate> delegate;
#end
when you set the data you're passing to the second controller you can also set a pointer to the previous one.
The "recommended" way of doing this is using a delegate. Have the first view controller set itself as the delegate of the new view controller during the -prepareForSegue: call, then when you're done, you call whatever delegate methods you've defined.
This is a bit more work than tightly coupling the two controllers, but it actually saves time if you ever find you need to use the controller in a slightly different way. If you watch the WWDC'11 video on using IB and Storyboards, they actually go through this pattern in depth and include code examples and demos, so I recommend taking a look at that.
I've been studying all of the variants to this question of how to pass data from one view controller to another and have come to see that Apple's Second iOS App Tutorial has not only the code but a lovely explanation of everything involved.
The way I am designing my code, with several view controllers, that interact, I have the need to pass data between the view controllers. The way that I am doing it is to "pass a reference", make a pointer, to the target view controller in as a method argument like below:
-(void)aMethodToSetUpInterfaceElements:(UIViewController*)targetCV
Is there anything wrong with this, or do I need to watch out? It works well on a functional level, but what about the design?
There's nothing really wrong about this.
If it works for you, than it's ok. Just make sure to have a weak reference to the view controller, otherwise you could have a memory leak with retain cycle. Read this for more information: http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
Speaking about design, it's really depends of each case. I could't say preciselly because you didn't give more informations about the funcionality that you are trying to achieve.
Maybe if you want to make your code more generic, to be used in other places or projects, you might consider to perform a delegate to your view controller, but this depends of your views hierarchy and its design. To see more information about passing data between viewControllers, please see this: Passing Data between View Controllers
I don't think it is a good idea to pass a view controller in order to transfer its data if you don't have enough reasons. I tend to exposing the minimal knowledge to another object.
For example, say you have two view controllers controllerA and controllerB.
If all you need is just to pass some data from controllerA to controllerB, you pass the data, which might be a NSData, a NSArray, a NSDictionary or your custom data structure. You should not pass the whole controllerA as an parameter to controllerB. Although you can access the data by using the controllerA.data getter, you have exposed too much knowledge about controllerA to controllerB, which may unconsciously ruin your design by increasing the coupling between controllerA and controllerB.
If you are aiming at handling the view transitions, that may be a good reason to pass a view controller as the parameter. So that you can make good use of its -presentViewController:animated:completion: to present a modal view, or push it into a navigation controller, or you probably want to get a reference to its view property and customize your own UI presentation.