views:

197

answers:

3

I have an UITabBarController with two tabs:

  1. UINavigationController
  2. OptionsViewController : UIViewController

How can I reach data (ie. UILabel.text) set in OptionsViewController, in a new added modal View which has been invoked from UINavigationController?

Edit1:

Scenario: After launching app I select the second tab bar called "Options" where I fill up a textField. The label is set to value from textField. Next I select first tab bar called "Main" where I have a button. I click the button and new modal View appears. In this new modal View I'd like to show the value from textField

A: 

In your OptionsViewController, create a property:

@property (nonatomic, retain) UILabel *mylabel;

then after creating your OptionsViewController, but before displaying it, set the mylabel property. (Or perhaps you just want the text, so you can use an NSString* property.)

Edit:

So you probably want to do something like this:

OptionsViewController *vc = [[OptionsViewController alloc] init];
vc.mylabel = mySomethingLabel;
[self presentModalViewController:vc animated:YES];

So after creating the object, you set the property, and then you display the view controller.

Emil
Yup, I have @property in OptionViewController. The problem is how to get that value from different Controller
falkon
See my prior solution here: http://stackoverflow.com/questions/2914543/access-uitableview-from-view-get-a-value-and-come-back-iphone/2915659#2915659
iWasRobbed
@Rob: IMO globals should be used as a last resort.
Emil
You know what they say about opinions... :)
iWasRobbed
A: 

I usually set IBOutlets in each of my viewcontrollers which point to the other controller. So if I had view controllers A and B. A has an IBOutlet to B and B to A. Then whenever I want to access anything in B from A i just use a dot operator on B.

In your example UINavigationController would #include "OptionsViewController.h" and have an ivar IBOutlet OptionsViewController * ovc (which is set in IB) and then any instance variable from your options view controller can be referenced as ovc.UILabel.text from the navigation controller. This process can be reversed to access values from your navigation controller in your options view controller.

Example Navigation Controller (.h):

#include "OptionsViewController.h"
@interface UINavigationController // (whatever the name of this class is)
{
OptionsViewController * ovc;
}
@property (nonatomic, retain) IBOutlet OptionsViewController * ovc;
@end

Example OptionsViewController.h:

@interface OptionsViewController 
{
UILabel * label;
}
@property (nonatomic, retain) IBOutlet UILabel * label;
@end

Then from UINavigationController (.m) you can just write ovc.label.text to access the text.

thelaws
instead of @implementation should be @interface. Anyway doesn't work for me...
falkon
I don't see any reason to use Interface Builder.
Emil
+1  A: 

I love MVC, but I'm not an absolute purist to the point of hurting yourself to accomplish a fairly trivial task, so the answers you've gotten here are good and useful. However, by creating an ivar to refer back to a specific type such as a label or other view controller, you are coupling things together that aren't necessary to couple. What you could do instead is make your first tab view controller a delegate of your second tab view controller. So do something like this in your app delegate.

OptionsViewController *optionsViewController = // ... get this from the tab view
FirsTabViewController *firstTabViewController = // ... same here

[optionsViewController setDelegate:firsTabViewController];

Which means that you need an ivar in your OptionsViewController:

@property (assign) id delegate;

Then, when whatever event you want to trigger the change occurs in your options view controller, see if the delegate can respond to a selector you've named. For example:

- (void)someEventHappenedLikeTyping:(id)sender;
{
    if ([delegate respondsToSelector:@selector(setOptionsString:)]
        [delegate performSelector:@selector(setOptionsString:) withObject:[label text]];
}

Notice you never specified any specific object types. You just check to see if the delegate (which was declared as id) can respond to that selector. If it can, it does what it's told and just is silent otherwise.

For this to work, you need an ivar for the optionsString in your FirstTabViewController and so it would be declared in the header as:

@property (copy) NSString *optionsString;

and then @synthesize it in the .m. This causes -setOptionsString to become a valid selector that will get called in the -someEventHappenedLikeTyping method.

Anyhow, now, if you ever need to to change which view controller references which, you don't have to go into the header and change the type of ivar referenced. You simply need to implement the selector (this is known as an informal protocol, by the way) in the view controller that is a delegate of your options view controller.

Just some food for thought there. Hope that helps. There is further de-coupling that could be done in the code I've added, but again it may be overkill for such a simple task. Let me know if you need clarification or want to understand what I mean by further decoupling.

Best regards,

p.s. Sometimes needing to share data between two tab bar view controllers, means you have a design flaw. If you are wanting to store preferences from your options view, you should just call

[[NSUserDefaults standardUserDefaults] setObject:[label text] forKey:@"option1"];
[[NSUserDefaults standardUserDefaults] synchronize];

Then you can pull from the NSUserDefaults back in your main tab with;

NSString *option1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"option1"];
// Do something with option1
Matt Long
Thank you for the answer. It seems little different from I've done already, but I think it might be usefull too. I try this concept ASAN :)
falkon