Accessing strings through segues on ios 5 - ios

I've got a question concerning my Storyboard. I want to change the value of a string which is in ViewA through a segue. That means that ViewB should do the segue and in preparation for that changing the value of the string in ViewA. My problem is now, that the value of my string stays unchanged.
ViewA.h file:
#interface NewViewController : UITableViewController <MKAnnotation>
{
NSString *longString;
}
#property (weak, nonatomic) NSString *longString;
ViewB.m file:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"transmitCoordsToNew"])
{
NewViewController *controller = (NewViewController *)segue.destinationViewController;
controller.longString = [NSString stringWithFormat:#"%f", segueLong];
}
}
Any idea why the variables stay unchanged or why I can't see any changes on further operating in ViewA?
Thanks in advance,
Phil

I'm not sure where your variable segueLong comes from, but having a weak reference to longString is most likely what's causing the problem. Change that to a strong reference and see if it works then.

If in prepareForSegue your NewViewController *controller is receiving a valid (non nil) value from [NSString stringWithFormat:#"%f", segueLong]; I am about 90% sure that the 'weak' property attribute is responsible for the value turning to nil.
Here's why!
[NSString stringWithFormat:#"%f", segueLong] has a scope limited by the prepareForSegue method, also it has no owner (aka no reference is counted for it). Even if segueLong has an owner and will not be released by arc, the resulting NSString from stringWithFormat does not!
What you need to do is change weak, to strong.
:
#interface NewViewController : UITableViewController <MKAnnotation>
{
__strong NSString *longString;
}
#property (strong, nonatomic) NSString *longString;
This ensures that the string generated by NSString stringWithFormat will belong to your NewViewController!

Related

How to access array variable value in the child view

I am trying to access an array defined as property on the parent view from child view and I get an empty array. here is what I did. could someone shed some light please!
FirstTableViewController.h
#interface FirstTableViewController : UITableViewController
#property (nonatomic,retain) NSMutableArray *SomeItems;
#end
in my FirstTableViewController.m. I have code that initialized the SomeItems with values. This has been verified
On the FirstTableViewController view there is a button that displays a second SecondTableView
in SecondTableViewController.m I have
#import "FirstTableViewController.h"
#import "SecondTableViewController.h"
- (void)viewDidLoad
{
[super viewDidLoad];
FirstTableViewController * objParent;
NSLog(#"count = %i",[objParent.SomeItems count]); //this return 0
}
thanks in advance!
EDITED
ToDoListTableViewController.h
#interface ToDoListTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *toDoItems;
- (IBAction)unwindToList:(UIStoryboardSegue *)segue : (id) sender;
#end
ToDoListTableViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//Attempt to pass toDoItems to new view controller.
//CompleteTableViewController.toDoItems = [self.toDoItems copy]; //this line caused compiler error saying toDoItems not found on object of CompleteTableViewController
CompleteTableViewController * objChild = (CompleteTableViewController*)[segue destinationViewController];
if(objChild != nil)
objChild.toDoItems = [self.toDoItems copy];
//sorry for weird code, as I don't really understand how this method really works.
//but I have a feeling I am just some inches away from getting it to work the way i want
}
CompleteTableViewController.h
#interface CompleteTableViewController : UITableViewController
#property (nonatomic,copy) NSMutableArray *toDoItems;
#end
CompleteTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"#%i record(s) in Complete Table View", [toDoItems count]);
}
Thanks again!
It is clear that you miss the basilar concept of the OOP.
You declared this:
FirstTableViewController * objParent;
but first of all it is not initializated and second it doesn't point to your instanced viewController.
Other things but that at this point become secondary are:
if you are using ARC, declare the property strong instead of retain;
method and variable should respect the Camel methodology so is not SomeItems but is someItems;
So if you are opening a viewController from another and you want access to that array, the best thing that you could do is pass that array and so have a property like this also in the second viewController:
#property (nonatomic,copy) NSArray *someItems;
and when you press the button in the first viewController, before push the second viewController:
secondViewController.someItems = [self.someItems copy];
Note that in the second view controller the array is not mutable, because probably you want just access to the informations. But this depend from you.
Is a little bit hard explain you more because i see that you are really a newbie. But, i hope to help you.
You need to pass a reference for the parent object through to the child on creation, or simply pass a reference to the array itself.
From Matteo suggestion, this seems to solve my issue
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
CompleteTableViewController *objChild = (CompleteTableViewController *)navigationController.topViewController;
if(objChild != nil){
objChild.toDoItems = [self.toDoItems copy];
}
}
thanks Matteo.
In the SecondTableViewController, you've declared the FirstTableViewController in viewDidLoad, but that does not mean it's pointing to your previously created FirstTableViewController (you've made no assignment). Before viewDidLoad is called, you need to pass the FirstTableViewController to the SecondTableViewController, assign it to a variable that's not local in scope, and then you can access the FirstTableViewController and/or its SomeItems inside viewDidLoad.
Without knowing more of your design or what you're trying to accomplish, it'd be best to pass SomeItems to SecondTableViewController as part of initializing it if that's all you need from FirstTableViewController. If the state of what you're accessing is going to change as you are going from controller to controller, I'd highly recommend you spend more time reading up on Model-View-Controller (MVC), delegation and possibly Key-Value Observation (KVO). You're missing some fundamental knowledge.
Edit: also agree on naming, SomeItems should be someItems.

Save Inputed textField data into a csv file

I want to save the inputed data from 3 textfields. I think I will store them in a CSV-file. The problem is that I want to display it in another viewController. or can I do it in a single view controller?
the user will type in their infon in the view controller1, then there is a called "Den här texten kommer att sparas" will show a NSString with all the information that is typed in, and that is what I want to store and show in some kind of list/table in the second view controller.
My question is: How can I access the NSString from the left viewController? Or is there an easier way to solve this problem, e.g. in a single view controller?
If you are changing the ViewController using a storyboard segue, the easiest way would be to pass it using the -prepareForSeguemethod. You have to set the segue identifier in the storyboard, select the segue and set your identifier text in the attributes inspector.
You will need to create propertys in your destination ViewController for the objects you want to pass.
Add this to your destinationViewController.h
#property (nonatomic, strong) NSString *tf1String;
#property (nonatomic, strong) NSString *tf2String;
#property (nonatomic, strong) NSString *tf3String;
Then import the destinationViewController.h file in your firstViewController.hfile.
#import "destinationViewController.h"
Then add the following method to your firstViewController.mfile
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_IDENTIFIER"]) {
DestinationViewController *destinationVC = [segue destinationViewController];
destinationVC.tf1String = [yourTextField1 text];
destinationVC.tf2String = [yourTextField2 text];
destinationVC.tf3String = [yourTextField3 text];
}
}
You may have to change some variables names in order to get this code working.

Updating label contents from one view in another

I'm very new to iOS development and I know there have been questions like this asked, but I can't seem to pull out of those examples what I think I need.
I'm trying to teach this to myself by coding a very simple mortgage calculator. I have two views, MortgageCalculatorViewController where the user enters the loan value, term and interest; and the ResultsViewController where this information is redisplayed, with the monthly payment, in labels. My current issue is I can't seem to figure out how to relay the calculated monthly payment value to the ResultsViewController.
I named the segue showResultsSegue.
In MortgageCalculatorViewController:
#import "MortgageCalculatorViewController.h"
#import "ResultsViewController.h"
#interface MortgageCalculatorViewController ()
#end
#implementation MortgageCalculatorViewController
NSString *paymentText;
-(IBAction)calculateMonthlyPayment
{
float rate = (self.interestRate.text.floatValue / 12) / 100;
long term = self.termInYears.text.integerValue;
float principle = self.loanAmount.text.floatValue;
float termedRate = pow((1 + rate), term);
float payment;
payment = (principle * rate * termedRate) / (termedRate - 1);
paymentText = [NSString stringWithFormat:#"%f", payment];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentLabel.text = paymentText;
}
}
#end
And in ResultsViewController:
#interface ResultsViewController : UIViewController
#property (nonatomic) IBOutlet UILabel *loanAmountLabel;
#property (nonatomic) IBOutlet UILabel *termInYearsLabel;
#property (nonatomic) IBOutlet UILabel *interestRateLabel;
#property (nonatomic) IBOutlet UILabel *paymentLabel;
-(IBAction)close;
#end
I've guided this approach on the information I found in Passing Data between View Controllers, but I'm still seeing no change after the segue.
Any help would be appreciated. Thanks.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentLabel.text = paymentText;
}
}
When preparing for a segue, the view has probably not been loaded, so paymentLabel is nil. Instead, declare a paymentText property on ResultsViewController and assign that value to paymentLabel in viewDidLoad.
New prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
controller.paymentText = paymentText;
}
}
Implementation for ResultsViewController:
#interface ResultsViewController : UIViewController
#property(copy, nonatomic) NSString *paymentText;
#end
#implementation ResultsViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.paymentLabel.text = self.paymentText;
}
#end
It's likely that your ResultsViewController has not initialized it's view elements, including the paymentLabel yet. Try explicitly calling view before setting the label text like so:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showResultsSegue"]){
ResultsViewController *controller = (ResultsViewController *)segue.destinationViewController;
[controller view];
controller.paymentLabel.text = paymentText;
}
}
Calling view will cause the view controller to load it's view elements, hence letting you set the label's text properly.
By far the easiest why to do this without using delegates, singletons or as mentioned above using the prepareForSegue, is using NSUserDefaults.
Save string:
[[NSUserDefaults standardUserDefaults] setObject:paymentText forKey:#"payment"];
[[NSUserDefaults standardUserDefaults]synchronize];
Read string:
NSString *readPaymentString = [[NSUserDefaults standardUserDefaults] stringForKey:#"payment"];
What you basically need to do here is to use the save code I provided in one view and the read code in the second view, simple.
I hope it makes sense.

Transferring String from UIViewController using Segue

I am doing the following:
#ViewController1.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Transferring");
guestViewController *controller = [segue destinationViewController];
[controller.label isEqualToString:self.num_value.text];
}
However when the view is loaded, the text does not run through or show up in the label. I have done this in past programs and it has worked on Xcode 4. However, for some reason in Xcode 5 it is not working for me. Is there something else that I need to implement to make this work in Xcode?
Add this to your guestViewController's header file :
#property (nonatomic, strong) NSString *value;
The your prepareForSegue method becomes something like this :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Transferring");
guestViewController *controller = [segue destinationViewController];
[controller setValue : self.num_value.txt];
}
isEqualToString is for comparison! Not to be used for assigning values.
Then in your viewDidLoad method, add this :
[textLabel setText : value];
[controller.string isEqualToString:self.num_value.text];
isEquelToString only check is controler.string is the same or not as self.num.value.text.
- (BOOL)isEqualToString:(NSString *)aString
Returns a Boolean value that indicates whether a given string is equal
to the receiver using a literal Unicode-based comparison.
Read the apple documentation
your can pass your string to the another controller like this:
In guestViewController's h file :
#property (nonatomic, strong) NSString *theStringWhatYouWantToGet;
and in prepareForSegue:
controller.theStringWhatYouWantToGet = self.num_value.text;

Passing Data from one View to another (Storyboard, iOS)

This is what I got so far.
mainview.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender(id)sender {
secondView *secView = [segue destinationViewController]
secView.ext = #".com";
}
secondView.h
#interface secondView : UIViewController {
NSString *ext;
}
#proper (nonatomic, retain) NSString *ext;
#end
secondView.m
-(void)viewDidLoad {
NSString *url = [#"www.google" stringByAppendingFormat:ext]
}
And its returning a error saying ext is null... what am I doing wrong?
Did you try to turn ext into a property instead? My understanding is that the "dot" notation essentially turns your code into
[secView setExt:#".com"]
So turn SecondView.h into
#interface secondView : UIViewController
#property (nonatomic, copy) NSString *ext;
#end
And don't forget to #synthesize it in your .m file
Check the followings:
Make sure #synthesize ext; is in SecondView.m
In Storyboard, have you linked the segue correctly?
In Stodyboard, is the viewController that represetns SecondView defined as a class of SecondView?
Make sure that you are calling the SecondView via prepareForSegue:sender method (i.e. SecondView doesn't get called by pushViewController:animated somewhere else in your code).
Put a breakpoint at the line:
secView.ext = #".com";
and make sure that the ext ivar is properly set after the assignment. If it's not, you might be specifying that the accessors use a different ivar in your #synthesize directive for ext, or you might have provided a setter -setExt: that doesn't properly set the ivar.
If ext is set properly after the assignment, perhaps you've got two different instances of secondView. That used to happen a lot when people used .xib files -- they'd create one view controller in code and have another instance of the same class in their .xib file. I wouldn't expect that to be the case here since you're getting secView straight from the segue, but it's worth thinking about.
There are two views: view1 and view2.
Add view2.h file in view1.h
init object of view2 and set their variable.

Resources