Passing Data(String) from Child View Controller to Parent VC using easiest Way .
i tried a Couple of ways , but got lost , can some one tell me the best way .
Srikanth is correct. If you have a segue from a view controller (our "first" view controller) to another (our "second" view controller), all you need to do is to create a property in the second one that points to the first one. You will just have the first view controller make sure to set that pointer before it performs the transition. Having done that, the second controller can update properties or invoke methods of the first controller.
For details, see Configuring the Destination Controller When a Segue is Triggered in the View Controller Programming Guide for information on how to set a property in the second view controller (in this case, that property will be a weak pointer to the first controller) in prepareForSegue. Then, as Srikanth says, the second controller can use that pointer to update properties in the first one.
So, in your second view controller, have a property (note carefully, it should be weak) that points back to the first view controller:
In SecondViewController.h:
#class FirstViewController;
#interface SecondViewController : UIViewController
#property (nonatomic, weak) FirstViewController *firstViewController;
#end
Then in the FirstViewController.m:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"YourSegueIdentifierHere"])
{
[segue.destinationViewController setFirstViewController:self];
}
}
So, if your first view controller had, for example, a property of favoriteColor:
#interface FirstViewController : UIViewController
#property (nonatomic, strong) NSString *favoriteColor;
#end
Then, the second view controller could use its firstViewController property to update this favoriteColor, like so:
self.firstViewController.favoriteColor = #"Blue";
Clearly:
Replace FirstViewController and SecondViewController with the appropriate class names;
Make sure that your second view controller's .m file does an #import of the first view controller's .h; and
Make sure you've specified a segue identifier in Interface Builder for your segue from the first controller to the second one and adjust the prepareForSegue above, replacing YourSegueIdentifierHere with your identifier.
In iOS 6, you can also accomplish this via an unwind segue. You'd just have the prepareForSegue of the second view controller update the property of the unwind segue's destination controller (i.e. the first controller). What's nice is that unwind segues can go back an arbitrary number of levels, so for more complicated scenarios, it's very nice. It is iOS 6, or higher, only, though.
To do unwind segue's, first you must define an unwind action in the first view controller (identified as such by the combination of the IBAction return type and the UIStoryboardSegue parameter), e.g.:
- (IBAction)done:(UIStoryboardSegue *)segue
{
// do any clean up you want
}
Then, the second (or third or ...) view controller can create an unwind segue by control-dragging in Interface Builder from a button to the exit icon in the scene's dock. You can have the controller from which you're unwinding do the logical prepareForSegue to pass information back to the first view controller.
By the way, you used the terms "parent" and "child", but I wanted to make it clear that I assumed that you were not talking about the more advanced topic of view controller containment, in which a view controller is invoking other view controllers to facilitate the presentation of a single screen of information (as opposed to transitioning between different scenes in an app). As rdelmar notes in our comments below, the terms "parent" and "child" controllers, strictly speaking, more properly imply that one is using view controller containment.
Obviously, if you are using view controller containment, then clearly the discussion of segues, prepareForSegue, etc., don't apply. Furthermore, a properly implemented container view controller guarantees that the child controllers can actually use the UIViewController property of parentViewController, without needing to define our own property to reference the parent. All you need to do is to cast/define parentViewController to be the right subclass, and then you can access your subclassed properties very easily.
Best way is to have a property in the child view controller of type id or UIViewController. Set that value to parent view controller when you are creating the child.
Once you have access to parent view controller in the child view controller you can access its methods or properties.
Related
In my interface I need to provide two NSTableViews in the same window that are structurally the same, but present different data to the user. I'm using storyboards and to do this, I've placed two Container Views in the view controller of the window. I then added a single view controller to the storyboard (outside of the window's view controller) and into that controller placed an NSTableView.
A couple of storyboard screenshots to illustrate:
The NSTableView is inside the Lineup View Controller, which has its own interface and implementation. The two Lineup View Controllers are binded to the container views within viewDidLoad of the Game Board View Controller like so (showing the code for only one of the attachments):
homeLineupView = [self.storyboard instantiateControllerWithIdentifier:#"Lineup View"];
[self addChildViewController: homeLineupView];
[HomeLineupContainerView addSubview:homeLineupView.view];
I'm able to successfully populate the two table views using notifications to provide the data that is unique to each table. The table views are functioning independently, as expected, with no problems.
Where I'm kind of stuck is how I now go about talking to the two table views from the view controller that manages everything else in the window (Game Board View Controller in the second figure). For example, how would I go about telling the table view inside Home Lineup Container View to select row 3? I have references to the Lineup View Controllers, but not the NSTableViews — unless there is a straightforward way to get those so I can call the methods directly. Or... do I need to set up notifications (or some other mechanism) for doing things like selecting a row, detecting a double click, etc?
Thanks!!
Adding a little more information about where I am confused
When I step through my code in the debugger I can "see" the table view inside the NSViewController that references the enclosing container view (see below).
You can also see my very incorrect attempt at using tableView directly to selectRowIndexes. 'visitorLineupView' is defined like so:
#interface GameBoardViewController : NSViewController <NSOpenSavePanelDelegate> {
:
:
NSViewController *visitorLineupView;
NSViewController *homeLineupView;
:
:
}
And the tableview itself is defined like so:
#interface LineupViewController : NSViewController <NSTableViewDataSource> {
:
:
IBOutlet NSTableView *tableView;
:
:
}
So, the procedural C programmer in me sees all this and wants to grab that 'tableView' pointer and use it directly to send it 'selectRowIndexes' message. But I know that conceptual rules of MVC are throwing up roadblocks I'm having a difficult time scaling.
Say you have a 2 subclass of tableView controller.
They both have the same header and footer view on top of the bottom of the header. They both implement pull to refresh.
They both have some common features.
The only different is one is for displaying the whole businesses, the other is for displaying only businesses you bookmark.
It looks like they both need to have the same parent class and the different is resolved on the child class. The differences are minor anyway.
I suppose the parent has it's own XIB, the children has it's own XIB.
Hmm... How would that work out? With the exception of container UIViewController, each controller should view a fullview of content. So which view should we display? The child or the superClass? Should child view add it's superclass subview?
Anyone have ever tried that?
Any code sample on the web that use this approach?
It sounds like, based on the business logic you explain, that everything is in common, except the list of data you're presenting. You could expose a property on your UITableViewController subclass to set the business objects that your tableview presents:
#interface JTBusinessesTableViewController : UITableViewController
#property (nonatomic, strong) NSArray *businesses;
#end
The code that instantiates this class would set the business objects:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self bookmarkedBusinesses];
[self.navigationController pushViewController:businessListings animated:YES]
The code for displaying all businesses isn't going to be much different:
JTBusinessesTableViewController *businessListings; //Instantiate from XIB or Storyboard
businessListings.businesses = [self allBusinesses]; // Here we assign all of them
[self.navigationController pushViewController:businessListings animated:YES]
You're just selectively giving this view controller, the business objects to display.
As we all know, table views in Cocoa Touch are one of the niftiest pieces of framework elements that's out there. As a convenience, Apple gave us a nice view controller class to encapsulate the functionality of a table view in a vc, the UITableViewController.
At the same time, there are times that we want to utilize the functionality of a table view without having it take up the whole screen. However, there seems to be no way to do this by subclassing UITableViewController. Instead, I had to hookup a table view and manually subscribe to the UITableViewDelegate and UITableViewDataSource. If I try to subclass UITableViewController, my app crashes before it can even put the view on-screen...
My question is, is there something I'm missing? When subclassing UITableViewController, I hook up my custom table view to the tableView property in UITableViewController. Is there something else I have to do?
UITableViewController only adds minor conveniences over UIViewController: it creates and positions the table view, hooks up the delegate & datasource (to itself, generally), passes the view controller editing property through to the table, and does a couple of useful UI bits when the view appears. (See [the docs][1] for details.)
Just about all of the above are either A) things that you're needing to change in order to have a non-fullscreen table, or B) things that you can do in a line or two each, and which UITableViewController only does for your convenience. For cases like this, you're better off using your own UIViewController subclass.
Step 1: Subclass UIViewController instead of UITableViewController
MyTableViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
Step 2: Use interface builder to drop a tableView and custom View
Step 3: Declare the tableView property as IBOutlet in your MyTableViewController header file and bind it to the tableView in the interface builder
IMHO, This process would give you more flexibility.
I am using a utility application in storyboard. I also created a third viewcontroller, which is accessed through a segue from the flipsideviewcontroller. I want to add a value in the third viewcontroller to an NSMutableArray that exists in the mainviewcontroller. I have played around with "delegation", but I have not been able to get it to work. My question is, how do I access my array that is defined in the mainviewcontroller from the third viewcontroller? Thanks.
When you create the 3rd view controller you can set a weak property that points to that array. Or you can define a delegate protocol that the 3rd view controller has a reference to, but the main view controller implements:
my3rdviewcontroller.delegate = mainViewController;
then in my3rdviewcontroller:
[self.delegate addValue:myValue];
and of course mainViewController implements the addValue: message.
I'm attempting to use the new Storyboard feature, however I am confused about Storyboard Relationships? How are they different to IBOutlets?
Also how can I add my own relationship, to my own UIViewController subclass?
I have tried looking in the documentation but can't find much about them.
The way I understand it is: relationships are iOS's way of representing a 'parent-child' relationship and while that does seem quite recursive, an example of parent-child relationship is a UIViewController Container containing a UIViewController.
That's the theory anyway -- it's better understood using the UINavigationController. It is called a 'container' because it contains as many regular UIViewControllers in a 'stack' metaphor so you can do your normal UITableView drill downs and pop offs.
The key point is that the segue between UINavigationController and the first UIViewController in your stack, there is a 'relationship' while the segue between all the rest of the UIViewControllers is just a regular push segue.
The same thing is evident in the UISplitViewController -- it needs two view controllers (sometimes called content view controllers) from launch and these are connected up between the parent UISplitViewController (the container) and two regular (content) view controllers
(thus relationships are not like IBOutlets, but more like segues -- they are even in the 'segues' category of the standard view controller containers)
Now - we aren't allowed to subclass the standard view controller containers, but we are allowed to create custom view controller containers, but I can't for the life of me define a relationship in my custom view controller container!!!!!!!!!!!
so: "can I use them in my own controllers?" the answer is yet unknown (to me at least, and the documentation is thin at best)
Create a subclass of the UIStoryboardSegue like this:
#implementation JTARelationshipSegue
- (void)perform
{
return;
}
#end
Make a custom segue between your two objects and set the class as JTARelationshipSegue. In your view controller make the view controller perform the segue like this:
- (void)viewDidLoad
{
...
[self performSegueWithIdentifier:#"addChild" sender:self];
}
You need to have set the segues identifier in interface builder to addChild.
Impement prepareForSegue:sender so that it adds the segues destination view controller as a child of the current view controller, like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destination = [segue destinationViewController];
[self addChildViewController:destination];
...
}
You will need to have a different segue identifier for each child that you want to create (or another way of identifying the specific view controller.
This will make your storyboard file look prettier, and more readable, however you may do better to just load your other view controllers and add them as children in your view did load method:
- (void)viewDidLoad
{
[self addChildViewController:
[[self storyboard]
initiateViewControllerWithIdentifier:#"myIdent"]];
...
}
I wrote a few tutorials on how to use storyboards over on my site...
Part 1 of tutorial
Part 2 of tutorial
Perhaps that will help a little bit? In essence, the Segue relationships provides an identifier for the link between two items on your storyboard. You can use these identifiers to manage how things work.