Passing data from UIViewController to 1 back UIViewController - iphone

So I have this UINavigationController, I'm on the first moving to the next view, than I want to hit the 'back' button and to go back to the first view with the data that I saved into 'strAddress' on the second view. I want to present the data on the first view on 'lblShowStr.text'.
how can I manage to do that? I've searched all the web, found some people that wrote, but couldn't understand what they have been told there.
Thanks!

You can get a reference to the previous viewController in your navigation stack by saying:
NSArray *viewControllers = self.navigationController.viewControllers;
MyViewControllerClass *previousController = [viewControllers objectAtIndex:[viewControllers count] - 2];
You can then set a property on the 'previous' view controller to store your text, or even set the label outlet's text directly like this:
previousController.lblShowStr.text = self.strAddress;
It's not the best way to do it (the best way involves creating a custom delegate protocol or using NSNotificationCenter) but it's the easiest way.

In your first view controller you might have an NSString property called strAddress.
and you put that string into lblShowStr.text every time the view appears.
In your second view controller you might have a property pointing to an instance of view controller one. When you instantiate your second view controller you could assign the property on it to the first view controller.
secondViewController.firstViewController = self;
or
[secondViewController setFirstViewController:self];
Then when the user presses the back button viewDidAppear would get called for the first view and update the string.
I am assuming you don't want to store this data anywhere else e.g. in your model or nsuserdefaults etc.

Related

How to switch view controller under this circumstance

I have a view controller that I need to refresh it self so, I basically reload it with the following code.
-(void)check{
GameController*myNewVC = [[GameController alloc] init];
[self presentModalViewController:myNewVC animated:NO];
}
I can call the method above in gamecontroller and it works fine, but in a button sub class I use the method below and it doesn't work because nothing happens.
.h
#interface CellButton : UIButton {
}
.m
GameController*myNewVC = [[GameController alloc] init];
[myNewVC check];
What can I do to get this working?
I have a view controller that I need to refresh it self so, I basically reload it
Don't do that. Your view controller isn't refreshing itself, it's replacing itself, and it's hard to think of a reason that it should need to do that.
Put the code the loads the data in a separate method, and call that method on the existing view controller instead of creating a whole new view controller. For example, many view controllers that manage a UITableView will call the table's -reloadData method to tell the table to discard any cells that are currently visible and request new ones. No matter what kind of view(s) your view controller manages, you can do something similar.
I can call the method above in gamecontroller and it works fine, but
in a button sub class I use the method below and it doesn't work
because nothing happens.
That's most likely because you say you're using the code in a UIButton subclass, and the code says:
[self presentModalViewController:myNewVC animated:NO];
So, the button is telling itself to present the view controller. However, UIButton doesn't have a presentModalViewController:animated: method. I'm surprised that "nothing happens" -- I'd expect an exception due to the unimplemented method. It should work fine if you replace self above with a pointer to your view controller. Or, much better, put the code in an IBAction method in the view controller, set the buttons action to that method, and its target to the view controller.
(from your comment...)
There is a function in the button class that will dictate weather or
not the view controller will refresh it self.
That sounds like a poor plan -- in a well designed MVC application, logic that controls whether the view controller will refresh belongs in the view controller. Have the view controller enable/disable or show/hide the button based on whatever conditions control the refreshing behavior.

identify the name of previous UIView

I was wondering if it possible to find which view called the following function
- (void)viewWillAppear:(BOOL)animated {
//find here the name of the calling view
}
Is there any way to find which view called the new view?
In viewWillAppear directly not. If it's pushed on a UINavigationController, you can get the viewControllers and get the previous one.
if (self.navigationController){
NSArray* viewControllers = self.navigationControllers.viewControllers;
UIViewController* lastViewController = [viewControllers objectAtIndex:([viewControllers count] - 1)];
NSLog(#"%# is my last ViewController before navigationg to this ViewController", lastViewController);
}
Well if are using the navigation controller you can get the array of viewControllers which are pushed by:
NSArray *array = self.navigationController.viewControllers;
but this will give you the view controllers which has been pushed it will fail if are coming back from a view ie popped from navigation stack as in both case your
- (void)viewWillAppear:(BOOL)animated {
//find here the name of the calling view
}
will be called.
You can use presentingViewController for this, but the problem is this will return the memory address of the view controller rather than the name of the pointer.
One solution would be to assign a tag to the view property of the presenting view controller and then ask for that tag in your second controller:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(#"%i",[[[self presentingViewController] view] tag]);
}
In your first view controller:
[[self view] setTag:(someNSInteger)];
Needless to say, "views" don't call this, but rather iOS will call this when your view appears. And unfortunately, this is complicated because you might get viewWillAppear because some other view controller presented this view controller's view, or you might get this when a view controller presented by this view was dismissed or popped (depending upon modal vs push).
We can probably outline all sorts of sophisticated and complicated ways of solving this problem, but we should probably first step back and ask why you need to do this. What are you really trying to achieve? If you're just trying to coordinate interaction between view controllers, there are far better ways of doing that (e.g. delegates, setting view controller properties, etc.).
Update:
If you're trying to figure out whether the data has changed, rather than relying upon some "where did I come from" logic, I'd personally lean towards some mechanism where those data-modifying controllers or processes bear the responsibility for notifying your view controller of this fact.
The simplest way of doing that would be to employ a delegate design pattern, where your child view controller would have a delegate property, which is a pointer to your controller that needs to know about the data change, and the child controller would simply invoke that method when data has changed. In slightly more complicated scenarios, you might combine this delegate pattern with a formal delegate protocol (so that the child view controller doesn't need to know anything about the parent controller other than the fact that it conforms to a particular protocol), but some may say that this is not needed when just communicating between two specific and well-known view controllers. See Using Delegation to Communicate with Other Controllers in the View Controller Programming Guide.
In complicated situations (e.g. data could be changing in a variety of places or even asynchronously, for example during updates via a web service), I'll use the notifications design pattern, in which the view controller will add itself as an observer of a particular notification to be sent by the NSNotificationCenter and whenever the data is updated, the notification center will be told to post that particular notification, which will, in turn, be received by the observer, your view controller.

passing data to secondViewController

Trying to send some data form my previous ViewController. To be more clear trying to send the selected date of the Si-Calendar to my secondView.
I'm adding the Calendar to my view in this way:
CalendarMonth *aCalendarView = [[CalendarMonth alloc] initWithFrame:CGRectMake(0, 0, 320, 324) logic:calendarLogic];
[aCalendarView selectButtonForDate:selectedDate];
[self.view addSubview:aCalendarView];
How do I use selected date and send it to my secondViewController (a UIView in which I'll display the selected date)?
Add a date property to your secondViewController, and set it appropriately when you create the instance...
It is a bit unclear what the first or second viewController is, but in general you could use a delegate for this purpose. For an example on how to do this, take a look at this answer
There are many ways to exchange data between view controllers, just take them as objects.
first controller hold a ref of the second controller, and transfer data using variables and methods
use delegate,
use notification
etc.
i can see that you are adding the CalenderMonth as the subview to another view. So if you dont release it (until u create the second view controller), you can set the selectedDate of the calender month obj to an iVar of second view controller. Else Create a delegate for CalenderMonth class. Set the second view controller as the delegate of the CalenderMonth and do the necessary.

Trying to update UILabel with contents of UITextField on different view controller

I have two view controllers, one is MainViewController, the other is SetupViewController. I want a UILabel on MainViewController to set the text to the contents of a UITextField from the SetupViewController when a button is pressed in the SetupViewController.
In SetupViewController, I have this in the IBAction:
- (IBAction)donePressed:(id)sender {
MainViewController *mvc = [[MainViewController alloc] init];
[mvc.testLabelOnMVC setText:testTextFieldOnSVC.text];
[release mvc];
}
testLabelOnMVC (and testTextFieldOnSCV, with respective terms) is
#property (nonatomic, retain) UILabel *testLabelOnMVC;
and is also synthesized.
Every time I try, it doesn't work. Nothing happens, nothing changes. I have no errors or warnings. Can anyone help me out?
The view of your MainViewController does not exist until you reference the MainViewController's view property (which forces viewDidLoad to execute). You must reference the view (or otherwise force the view to be constructed) before you attempt to modify any UI objects in the MainViewController.
You are allocating a new MainViewController when you press the button, then you are setting the text of the label on this new controller, not on the MainViewController that your app is showing.
To fix this, create either and IBOutlet or iVar that points to the original MainViewController and set the text on that instead.
Easiest way is to create a #property in the main view controller and write the text in there. Then just read it in the second MVC's viewDidLoad.
The only views that MainViewController should worry about are the ones that it owns; it shouldn't be trying to access the view hierarchy managed by SetupViewController. Likewise, SetupViewController should not directly modify views in MainViewController's view graph.
The right way to do what you're asking is for the two controllers to talk to each other, either directly or via the data model. For example, let's say that your MainViewController instantiates SetupViewController. If that's the case, it'd be natural for mvc to set itself as svc's delegate, so that svc sends it a messages like -setupController:didUpdateTestStringTo:. MainViewController's implementation of that method could then save the new test string somewhere and update it's testLabel field.
Another example: MainViewController instantiates SetupViewController. SetupViewController contains a field where the user can enter a new value for the test string. Before exiting, SetupViewController writes the contents of that field into NSUserDefaults or some other common data storage. When control returns to MainViewController, that object reads the shared data and updates itself as necessary, including setting the new value for testLabel.
There are other variations on the same theme, but the common thread here is that neither view controller has to directly access views that it doesn't own.
You can change the text of the label if the view is already loaded. Instead of initializing the viewcontroller, retrieve it from the view stack if you are using navigation controller.
I dont know if your viewController is already loaded or not.

Check nibName of the previous UIViewController

I have a navigation based app. In a certain screen, I need to check from which screen the user came. I thought about something like
NSArray *viewControllers = [self.navigationController viewControllers];
int viewControllersSize = [viewControllers count];
if ([[viewControllers objectAtIndex:viewControllersSize-2] nibName] == #"Name") {
...
}
But the problem is that if the user clicks "back" from a certain screen, the view controller will be removed from the array defined above.
My current solution is having a global variable that tells me if the user came from a specific screen, but I suppose there is a more elegant solution, right?
Not sure what you meant with:
But the problem is that if the user
clicks "back" from a certain screen,
the view controller will be removed
from the array defined above.
Not all view controllers use same navigation controller?
If same UINavigationController is used for all UIViewControllers, you can use UIViewController parentViewController for this purpose. If going the opposite way, keeping reference to view controller you came from or maybe just [viewController class] (to string) would do the trick.