in an "OfferViewController.m" I have a locationManager function. In the locationManager function I get the currentLatitude and the currentLongitude. Now in the "OfferDetailViewController.m" I want to send the location via JS to a website.
My problem ist, that in the "OfferDetailViewController.m" I don´t get the location information from the "OfferViewController.m"
Hope somebody can help me... here is my code. Thanks!
OfferViewController.m:
#interface OfferViewController ()
#end
...
#pragma mark -
#pragma mark CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSString *currentLatitude = [[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.coordinate.latitude];
//NSLog(#"locationManager - latitude: %#", currentLatitude);
NSString *currentLongitude = [[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.coordinate.longitude];
//NSLog(#"locationManager - longitude: %#", currentLongitude);
OfferDetailViewController *offerDetailViewController = [[OfferDetailViewController alloc] init];
offerDetailViewController.longTest = currentLongitude;
offerDetailViewController.latTest = currentLatitude;
}
#end
OfferDetailViewController.m:
#interface OfferDetailViewController ()
#end
...
#synthesize latTest;
#synthesize longTest;
...
- (void)webViewDidFinishLoad:(UIWebView *)offerUrl {
NSLog(#"webViewDidFinishLoad");
if ([[self.offerUrl stringByEvaluatingJavaScriptFromString:#"document.readyState"] isEqualToString:#"complete"]) {
// UIWebView object has fully loaded.
NSLog(#"UIWebView object has fully loaded.");
NSLog(#"webViewDidFinishLoad - longTest: %#", longTest);
NSLog(#"webViewDidFinishLoad - latTest: %#", latTest);
...
}
}
Since you are dealing with two view controllers, it is recommended to use segues. Xcode's storyboard files allow you to use segues visually, with a little programmatic assistance.
Steps
Here are a few steps to accomplishing what is asked in the question. These will be discussed below in the rest of the answer.
Create a segue in storyboard
Name the segue in storyboard
Create a prepareForSegue: method & set the variables in the receiving view controller
Making a segue in storyboard
First, I'd recommend linking the two view controllers via one of these segues. To do this, go to your storyboard and have a look at your starting view controller (in this case, it's OfferViewController). Locate the button or cell (some UI element) that will trigger the transition. Then hit the "control" button on your keyboard and click on that UI element. A blue line should appear. Drag that line across to the view controller that you want to move to (in your case OfferDetailViewController), and release. Then, from the options that are displayed, choose which transition type you prefer (typically, if the view is a detail view, you want to choose "push", but unless you have a UINavigationController setup, this will throw an error. Choose "modal" if you have no idea what I just said there). Your end result should look like this:
Naming a segue in storyboard
Next, you want to name your segue so you can access it programmatically. Go ahead and click on the center icon of the segue. Ihe right side bar in Xcode should flip to a view that looks something like this:
Now, in the Identifier box, type in your segue name. This can be anything you want, but remember what it is because we will use it later. I'd also recommend outlining a general pattern for segue identification, so that if you have many segues, you don't have to keep referencing the storyboard, but for just getting something started, that's not necessary to stress over.
Setting the variables in the receiving view controller
This bit we've got to do programmatically. Apple has a handy function that is defined in UIViewController (thus, can be accessed from any UIViewController). The name if this function is 'prepareForSegue:'. Let's take advantage of that.
# pragma mark - SEGUE PREPARATION
/**
* This method prepares to transition from THIS contoller to another controller that will
* display the data in more detail.
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
/* Verify this is indeed the segue you want; replace "YourSegueName" to whatever you
named your segue. */
if ([[segue identifier] isEqualToString:#"YourSegueName"]) {
OfferDetailViewController *receiverController = (OfferDetailViewController *)[segue destinationViewController];
/* here you can set whatever variables you want in 'receiverController'. These
will be accessible in the viewDidLoad: method. An example is given below. */
[receiverController setWhateverVariable:valueOfWhateverVariable];
}
}
And that's it! The data should be transferred to your new view controller, and you should be good to go!
You can store those double (or strings) values (Lat & Long) in your NSUserDefaults and grab them from your Detail View controller.
The location manager just has to be called before the detail view is shown. Make a key that you can reuse and whenever you re-save your user's new coordinates it will over-write the last ones.
ex.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *latitudeKey = #"somelatitudekey";
NSString *longKey = #"..";
[userDefaults setObject:currentLatitude forKey:latitudeKey];
[userDefaults setObject:currentLongitude forKey:longKey];
and to retrieve...
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *latitudeKey = #"somelatitudekey";
NSString *longKey = #"..";
Double latitudeOnNextView = [userDefaults objectForKey:#"latitudeKey"];
Double longitdeOnNextView = [userDefaults objectForKey:#"longKey"];
Be sure to only store the coordinates (double or string whichever you prefer) into the user defaults - it wont work if you try and save the entire location object that the location manager returns.. unless you serialize it.
Also, when you call for the coordinates in the detail view they very well could be null if the location manager hasn't finished updating the user's location by the time you save them into the user defaults so check for those nils accordingly. **This is most likely the issue you are having now -- when you call your new view controller those values you are passing aren't there yet.
Related
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I need to pass data between two ViewControllers but without UIButton, in a few words, I need to access a variable which is in other ViewController.
My code is:
LoginViewController *lvc;
NSString name=lvc.name;
This specific case might be a little easier than delegates.
From what I see, you're trying to pass login credentials (name/login/password/something). I would use two things depending on the actual matter here.
Either NSUserDefaults or -performSegueWithIdentifier:
NSUserDefaults is a file that is loaded in every app that you can read and edit, simply using the following commands :
Setting a variable :
NSString *aName;
[[NSUserDefaults standardUserDefaults]setObject:aName forKey:#"userName"];
Getting a variable :
NSString *aName = [[NSUserDefaults standardUserDefaults]objectForKey:#"userName"];
Note that you can save the following objects NSDictionary, NSArray, NSString, NSNumber, NSData, and probably a couple that I'm forgetting but someone can edit if I do.
Note that this file is loaded at every startup, so you don't wanna use that as a database but more of a small-sized storage easy to use, like for user name, preferences/settings, and stuff like that.
The other way is using performsegue between two controllers, but that requires storyboards.
Drag a segue between two of your controllers, name it (for example) fromLoginToHome. I'm assuming that the flow goes from the login controller to the home controller.
when you move between the two views (when the user presses "Login" for example), call this method
[self performSegueWithidentifier:#"fromLoginToHome" sender:self];
Then you'll need to implement this method, that is usually there but in a comment block (it's always like that when you create your Vc)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"fromLoginToHome"]){
HomeViewController *vc = (HomeViewController*)segue.destinationViewController;
vc.myName = _myName;
}
}
Xcode using delegate to pass data between controllers This is for child to parent by usuing delegates
And For parent to child,you can use segues simply.
HTH!enjoy Coding.
You can have a look of delegate method in here delegate. can you tell me if you are looking for delegate or not
Try using as below
FirstViewController.h
#interface FirstViewController: UIViewController
- (void)GetItNow;
FirstViewController.m
- (void)GetItNow{
NSLog(#"I acheived"); }
- (IBAction)goToSecondView:(id)sender {
SecondViewController* Second= [[SecondViewControlleralloc] initWithNibName:#"SecondViewController" bundle:nil];
rqVC.addId = self.addId;
[self.view addSubview:Second.view];
}
SecondViewController.h
#property (nonatomic, assign) id delegate;
SecondViewController.m
- (IBAction)Action_LoadFunds:(id)sender {
[self.view removeFromSuperview];
[_delegate GetItNow];
}
I am currently working on a project that requires a list of customers to be displayed in a UITableView, the associated cell then segues to a TabView to display a detailed customer record in a tabbed ui.
I have setup the story board with the required TableView and populated fine. The TabViews all setup and I have added a custom class to the main TabView controller which can take the ID (required to interrogate service and return further data) and Customer Name. I have also added a UIViewController for the first tab in which I need to get the ID value.
I can't seem to get hold of the ID or Company Name that is passed. I have tried importing the .h file of the UITabView. I know the UITabView .h file is being populated with the values as in the .m file I am using the Customer Name to update the title of the Navigation Bar. However, whenever I breakpoint on line that gets the ID in the .m file for the individual tab, it always returns nil.
I am using the following code to try and get this value:
companyTabController *headerData = [companyTabController alloc];
_companyName_lbl.text = headerData.companyName;
_companyID_lbl.text = headerData.ID;
I have tried several variations of the above and all to no avail.
You can also use NSUserDefaults to save the data, I think that is the simplest way to save the data throughout the app.
From the code you posted, the headerData is a new instance. So the companyName and the ID will be nil unless you assign some value to them.
Since, you mentioned that you are able update the navigation bar title, try using the same object for fetching the values in this controller as well. (Maybe you can use a singleton object)
If your segueing you have to use the prepareForSegue:sender: method as such:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
companyTabController *companyTC = [segue destinationViewController];
companyTC.companyName_lbl.text = headerData.companyName;
etc
}
if your not segueing you will have to instantiate it as such :
- (void) didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
companyTabController *companyTC = [self.storyboard instantiateViewControllerWithIdentifier:#"CopmanyTabController"];
companyTC.companyName_lbl.text = selectedCell.textLabel.text or = headerData.companyName;
[self.navigationController pushViewController:companyTC animated:YES];
}
I'm new to objective C and design patterns like MVC, protocols and so on but this is it:
I am trying to write an iOS app within two viewcontrollers: the first has a textview where the user can write into, and the second has a UISwitch that triggers on "Value changed" and saves a file.
If I toggle by hand the switch on the SecondViewController it will save the file and that's ok.
But I wish the file could be saved from the FirstView just when the user types a specific word, it auto-switches to the second view, and auto-activates the UIswitch and all the method already behind it.
I still can't get the two interfaces working this way. Thanks everybody in advance for helping. Cheers!
this is connected in SecondViewController.h in the storyboard
-(IBAction)toggleFileSave:(id)sender;
and it is implemented as usual...
#interface SecondViewController ()
#property (nonatomic,weak) IBOutlet UISwitch *mySaveFileSwitch;
#end
- (void) toggleFileSave:(id)sender {
// how do I execute this code when the user
// type a specific word in the first view??
}
Create a BOOL flag in your SecondViewController.
Set it when the specific word is typed and push the view controller.
In the viewDidLoad of SecondViewController check the flag condition.If it is set call the required method.
When the specific word is typed:
ViewController2 *viewController = [ViewController2 alloc]init];
viewController2.flag = YES;
[self.navigationController pushViewController:viewController2 animated:YES];
In your text field delegate (add one if it doesn't exist) add this method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
/* at this point the user finished editing */
NSString *currentText = /* read text field value */
if ([currentText isEqualToString:/* the magic word */]) {
/* save the file, present a view controller, etc. */
}
}
Check UITextFieldDelegate to know the available methods, you may need more than one to get the desired behaviour.
If you want to load the second view controller in order to show the UI and the save the file you can do as サンディープ said in his or her answer:
SecondViewController *controller = [SecondViewController new]; /* init as usual */
controller.saveOnLoad = YES;
[self.navigationController pushViewController:controller animated:YES];
Then, in SecondViewController:
- (void)viewDidLoad {
if (self.saveOnLoad) {
/* save file in async block */
/* set switch on */
}
}
If you don't need to show the second view I'd move the saving functionality to its own class and use it from the first controller, showing just a confirmation message for instance.
I'm developing an app that will support multiple languages and I'm looking for the best way to set the different languages.
The app works with a UINavigationController. In the first ViewController you can select the language pressing a UIButton and then in the following view controllers the labels' texts would be changed to the corresponding language.
The way I'm doing it right now is by changing the value of a BOOL property when I create the instance of the new ViewController depending on the UIButton sender tag.
FirstViewController.m
-(void)goToSecondVC{
SecondViewController *secondVC = [[SecondViewController alloc]init];
if ([sender tag] == 1) {
secondVC.english = YES;
}else{
secondVC.english = NO;
}
[self.navigationController pushViewController:startScreenVC];
}
SecondViewController.m
-(void)viewWillAppear:(BOOL)animated{
if(self.english){
self.myLabel.text = #"This text will be in English";
}else{
self.myLabel.text = #"This text will be in Spanish";
}
I know this is probably not the best way to achieve this task. What would you recommend, notifications, delegation, singletons? I'm looking for a kind of global variable that could be written and read from every ViewController
You should be using localization for this.
You can get the language like this:
NSString *language = [[NSLocale currentLocale] objectForKey: NSLocaleLanguageCode];
Take a look at this this tutorial for localization:
http://www.raywenderlich.com/2876/localization-tutorial-for-ios
or this SO ansawer
The implementation is straightforward and correct.
Since you want to have this information known to every view controller, a better approach is to use KVO and a store for the language info value.
For example, save it to NSUserDefaults. Then from any view controller your could access it.
Then if some view controller wants to get notification when this value gets changed, it could observe the NSUserDefaults object for that value. (with Storyboard, you could use a Shared User Defaults Controller).
If you want to access the current language setting from any place in your app its worth taking a look at the Singleton design pattern. Here's an excellent summary.
You can also use the [NSUserDefaults standardUserDefaults] which is a predefined Singleton object or simply create your own.
So one of the users in here managed to show me how to pass data from a child view controller to a parent view controller via a string.
So now the string is passed, BUT, i want that value to stay displayed on the firstViewController after the app is closed and re-opened.
The value is saved in with NSUserDefaults by the way and with an NSLog i am seeing on the conosole it is saved in the apps folder but that value isnt saved onto the UILabel display.
It only displays it when i put save but then i close and reopen, it dissappears but in an NsLog it is still inside the app but not on display UILabel.
How can i address this ?
On my appDelegate.h i have a
#property (strong, nonatomic) NSString *sharedString;
To pass the secondViewController data to the firstViewController.
In the save method on my secondViewController i have a function related to the
AppDelegate.h declaration which is:
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
apiDelegate.sharedString = self.textFieldData.text;
And in my firstViewController i have a method which display the data from the second
viewController:
-(void) viewDidAppear:(BOOL)animated {
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
self.DisplayData.text = appDelegate.sharedString;
[super viewDidAppear: NO];
Is there something wrong which isnt keeping the data intact after app closes or am
I missing something here ?
So one of the users in here managed to show me how to pass data from a
child view controller to a parent view controller via a string.
First you need to establish some hierarchy as to how you get a childViewController from a parentViewController. One way to pass data from childViewController to parentViewController is using a delegate. The other could be using the KVC/KVO protocol. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
In this you can simply register an observer for the property defined in the childViewController and observe it's changes wherever you want (well, given the hierarchy is satisfied).
To save the value. You can simply save it using NSUserDefaults. I don't see any code in your post but you can simply define a key and save the value with NSUserDefaults using:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:sharedString forKey:#"sharedString"];
NSString *sharedStringFromDefaults = [defaults objectForKey:#"sharedString"];
Also,
AppDelegate *apiDelegate = [[UIApplication sharedApplication]
delegate]
Apple requires you to avoid such references in the application. It only constrains the app. Further, the sharedString is not required to be in the AppDelegate. Otherwise the AppDelegate will be filled with almost every other data structure you have shared in the app.
//add this code when you want to store string
[[NSUserDefaults standardUserDefaults] setObject:self.textFieldData.text forKey:#"sharedString"];
[[NSUserDefaults standardUserDefaults] synchronize];
//and when you want string than
self.DisplayData.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"sharedString"];