iOS Segue And Passing Data Back [duplicate] - ios

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.

Related

Calling a view controller class without popping up the view controller itself

I am upgrading my app version, hence needed to reduce two view controllers to one. Hence, I am calling the second view controller skipping the first one. But here I need to call the class of first view controller as there are some important declarations and implementations. How can I call first view controller's class without popping up its view controller.
This is confusing.
Why not taking all the initializing code from your first VC (copy-paste your properties, initialization in viewDidLoad etc.) to your second VC ?
Once you are done, get rid of the first VC as it is useless and make your second view controller the root.
A ViewController is meant to be "viewed", I suggest you don't just hide it, that's a really bad architecture.
If you don't need one view controller at all, then you can delete that View Controller from storyBoard, and also subclass your class as an NSObject class (lets call it DataProviderClass) instead of previously( UIViewController) subClass. It isn't a good idea to have a "dummy" view controller in a navigation Stack.
You can use your DataProviderClass class as a support file that can provide any data to your Second View Controller. And to perform calculations/methods in this class before launching your second VC, just run these methods in viewdidLoad method, by creating an instance of this NSObject class (DataProviderClass) and keeping a reference to it.
When you segue further, you can very easily even transfer the same reference of DataProviderClass.

Using storyboarding in xCode how can I change the value of a label from a different view?

I'm writing an app that uses storyboarding and I want to update the labels in one view by clicking a button in a previous view.
_label.text = variable1;
is the line I would use to change the value of label, which is in the next view, when I click the button. Using this method I can easily change labels in the same view as the button but it does nothing when I go to the next view and see empty labels.
I've tried looking everywhere and found similar issues but couldn't find anything that worked for me so any solution would be very appreciated!
Unfortunately, it is not possible to connect IBOutlets between different scenes in storyboard.
It is difficult to suggest some precise solution because you have to provide more details about the setup which you have. Still, it is possible to outline some possible solutions:
Using prepareForSegue
If the view controller which you want to modify appears after the segue is performed you can customise its appearance in prepareForSegue function.
Using delegation
You can assign the view controller which wants to modify another view controller as its delegate. For example, if ViewController1 wants to modify ViewController2:
#interface ViewController1: UIViewController {}
#property (nonatomic,weak) ViewController2 *controllerThatIWantToModify;
with such setup you can call:
self.controllerThatIWantToModify.label.text = variable1;
You use storyboards, so there must be a segue from your first viewController (with the button) to your second (with labels in it).
If it is the case, you can set up the labels of the second view controller from the prepareForSegue method of your first view controller.
This method is called with a segue object which has a destinationViewController property which is your second view controller.
If you have several segue from this viewController, you should check if it is the right segue and then set it up.
To do that you need to set up outlets that gives you access to the labels from the viewController.
Then you can either write a setUpLabelsWith:(NSString)text1 ... method in your view controller, or directly access the outlets from the first view controller (supposing their are not private).
Yes this supposes your second view controller has a custom class.

What's best practice to easily reuse bunch of code in multiple view controllers?

I'm rather new to programming and wondering about a certain (best) practice:
Let's assume we have an app with several view controllers. In our case, most of those need the functionality of alerting the user about certain circumstances, make use of an activity indicator or depend on other similar general functionality. So far I've learnt how to implement such methods but then just copied the whole bunch of code to each view controller when needed. Doing so, every view controller gets filled up with a lot of extra code. I know it's possible to make code kind of "global" by moving it to the top of a view controller, outside the class brackets. But as we need to ensure that certain subviews are added to the right view controllers when calling those methods I'm not sure yet what the best way to go - in general - would be.
Is there a commonly used practice that differs from my approach when defining such - let's say - alert behaviors (defining variable/constant and its needed methods) which are used in multiple view controllers?
Objective-C provides two general ways of reusing code:
Inheriting a base class, and
Using a shared function.
The first case is straightforward: if you need a specific functionality in several view controllers, make a base view controller with the shared methods, and then derive your other view controllers from it:
#interface BaseViewController : UIViewController
-(void)sharedMethodOne;
-(void)sharedMethodTwo;
#end
#interface FirstViewController : BaseViewController
...
#end
#interface SecondViewController : BaseViewController
...
#end
#interface ThirdViewController : BaseViewController
...
#end
The second case can be implemented either as a helper class with class methods (i.e. with + instead of -) or with free-standing C functions.
You should look to see what could be moved from the controller level to the view level. It sounds like you're reusing a bunch of views so I would create subclasses of UIViews that can implement themselves. Then in the view controller you can handle when the views should appear and the data associated with them but you don't need to rewrite how to implement the views.

My understanding of view controllers and subclasses

I recently asked a question regarding my incorrect use of instance variables on UIViewControllers. The answers I got brought to light another fundamental issue: I think I might be using UIViewControllers all wrong as well.
My typical storyboard looks something like this:
As you can see, each view controller has a custom class. One of those custom classes might look like this:
// SecondViewController.h
#import <UIKit/UIKit.h>
#import "MasterViewController.h"
#interface SecondViewController : MasterViewController
#property (strong, nonatomic) NSData *incomingData;
#end
// SecondViewController.m
#import "SecondViewController.h"
#import "ThirdViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// do stuff with data, then pass it on to next view controller.
}
#end
Each view controller is a subclass of MasterViewController. In MasterViewController, I'll usually put global things like user state validation, for example. That way every view controller in the app can validate user state without reimplementing it each time.
About that incomingData property...I wasn't sure how else to pass data between UIViewControllers without using a property on a custom class...hence three separate custom classes, each one not doing all that much.
So here's where it gets murky for me...
Should I be keeping important methods and instance variables in a "master" view controller so all other view controllers can subclass it and have access to those methods and variables? Or is that ridiculous?
Am I causing more work for myself by not using proper class extensions or categories? Would those help me keep things a little more streamlined and organized?
My current system works for the most part, but it can get unwieldy when I have lots and lots of view controllers, each with its own custom class.
Obviously, the first step which you may have done, and whether you've completely grasped or not, is to really understand the Model-View-Controller pattern. A pretty good tutorial I did with a quick google search is here: http://codewithchris.com/how-to-make-iphone-apps-mvc-one-pattern-to-rule-them-all/.
The next thing I'd suggest is that your controllers don't need to be subclasses of anything but UIViewController. There's a difference between the view hierarchy and the class hierarchy. In your storyboard, you're outlining a view hierarchy - which view/controller leads to the next view/controller. They can all be independent. They can still pass data even without being subclasses of each other, or of a previous controller.
You can still pass data directly through properties. Why not be more specific about what data needs to be sent? Instead of sending a generic NSData blob, specify what you need one controller to tell the next. For example, if you're passing in a username from one to the next, use:
#property (nonatomic, strong) NSString *username;
for the second controller, and in your first controller, set it:
self.secondController.username = #"my name";
If from the second controller to the third controller, you don't need the username, don't make it a property of the third controller. Maybe the third controller only displays a number:
#property (nonatomic, strong) NSNumber *someNumber;
From the second controller, just set its value:
self.thirdController.someNumber = #5;
Now, I like to use some global variables and methods. Those are sometimes useful when you have helper classes that don't need to be instantiated. One way to do this is to just have a class variable:
FirstController.h:
+(NSString *)defaultName;
FirstController.m
+(NSString *)defaultName {
return #"Default";
}
Then in second controller, you can do something like
self.username = [FirstController defaultName]
There are other patterns, like delegate patterns, where the second controller asks its delegate (the first controller) what the username should be:
self.username = [self.delegate username];
But for this you have to set up a protocol. Ray Wenderlich usually has very good tutorials: http://www.raywenderlich.com/46988/ios-design-patterns
What you have here is Strong coupling, which is considered to be a bad thing.
Lets say you want to create a new application, and you want to copy a view controller from the old application, at the moment it would be very difficult for you as you would have to modify a lot of things.
The goal is to achieve weak coupling, which means that every class in your project can work independently from one another.
You can store your data as a property on your App Delegate, which is a singleton, so you can get an reference from an any class using AppDelegate *appDelegate=[UIApplication sharedApplication].delegate;. Or you can define a new singleton object to store the data.
The pattern you are using is dependency injection, which many people prefer to the singleton pattern.
If all of your view controllers are inheriting from the same superclass (MasterViewController) and all have that same property then you can simply define the property in the superclass.

Handle UITableViewDelegate Events in different Controller

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.

Resources