how to pass a variable value to another view properly - ios

i have two views MainView and MainInvoicing
from MainView i am sending a int type variable value to MainInvoicing
this is my code
in MainInvoicing.h file i declared int type var
#property (nonatomic, assign) int myChoice;
in MainView.m file on a button click i am calling the MainInvoicing as
MainInvoicing *invoicing = [[MainInvoicing alloc] initWithNibName:#"Invoicing" bundle:nil];
[self presentViewController:invoicing animated:YES completion:nil];
invoicing.myChoice = 1;
from this my MainInvoicing is called perfectly, but myChoice is equal to zero '0'. while it should be '1'
i am receiving this value in MainInvoicing.m as
- (void)viewDidLoad
{
[super viewDidLoad];
[self Start];
}
and the start method is
- (void) Start
{
switch (myChoice)
{
case 1:
NSLog(#"value is %d",myChoice);
break;
case 2:
NSLog(#"value is %d",myChoice);
break;
default:
NSLog(#"Oooopppss...%d",myChoice);
break;
}
}
i am always on default part ….
where am i wrong or any suggestion to get the right value … please help…

You should assign value before you present view controller:
MainInvoicing *invoicing = [[MainInvoicing alloc] initWithNibName:#"Invoicing" bundle:nil];
invoicing.myChoice = 1;
[self presentViewController:invoicing animated:YES completion:nil];

As Greg said in his comment, it's all about order of code. If you look at your code you should see the order in which it is called.
MainInvoicing *invoicing = [[MainInvoicing alloc] initWithNibName:#"Invoicing" bundle:nil];
[self presentViewController:invoicing animated:YES completion:nil];
[self Start];
switch (myChoice)
{
case 1:
NSLog(#"value is %d",myChoice);
break;
case 2:
NSLog(#"value is %d",myChoice);
break;
default:
NSLog(#"Oooopppss...%d",myChoice);
break;
}
invoicing.myChoice = 1;
So you are trying to access the myChoice variable before you set it, which is why you are getting 0 instead of 1.
With all of that said, there is a possibility of your code working as it is written since the viewDidLoad function is not always called serially. But you should not expect it to always work and you should initialize variables before you call code that could use them immediately.
Accept Greg's answer, I was just adding a bit of explanation to the problem.

Related

iOS block function called twice

I have a block function defined as the below:
#property (atomic, assign) bool callInProgress;
//in implementation:
- (void)synchronize:(void(^)(void(^unlock)()))block {
if (!_callInProgress) {
_callInProgress = YES;
[_tableView setScrollEnabled:false];
block(^{
[_tableView setScrollEnabled:true];
_callInProgress = NO;
});
}
}
Then when I do:
[self synchronize:^(void(^unlock)()) {
}];
and I set a break point at that [self synchronize..], the break point gets hit twice no matter what! If I add a body:
/*break point on this line*/ [self synchronize:^(void(^unlock)()) {
NSLog(#"HERE");
unlock();
}];
HERE gets printed ONCE but the break point gets hit twice!
Any ideas why?
The breakpoint is being hit once when you reach the synchronize call, and once when you enter the callback block. Both are on the same line.

messageComposeViewController didFinishWithResult delegate method not being called

I have a view controller "Paircontroller" that presents an MFMessageComposeViewController, as so:
NSArray *recpts = [[NSArray alloc]initWithObjects:phone.text, nil];
MFMessageComposeViewController *mcontr = [[MFMessageComposeViewController alloc]init];
mcontr.body = #"Sign up for our app!";
mcontr.recipients = recpts;
mcontr.subject = #"hey!";
mcontr.delegate = self;
[self presentViewController:mcontr animated:YES completion:^{
}];
this view controller's interface looks as follows:
#interface PairViewController : UIViewController<UITextFieldDelegate,CustomIOS7AlertViewDelegate, UINavigationControllerDelegate, MFMessageComposeViewControllerDelegate>
#end
Within the view-controller's implementation, I have defined the delegate method - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
as follows:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
switch (result) {
case MessageComposeResultCancelled:
NSLog(#"Cancelled");
break;
case MessageComposeResultFailed:
NSLog(#"unknown error sending m");
break;
case MessageComposeResultSent:
NSLog(#"Message sent successfully");
break;
default:
break;
}
[self dismissViewControllerAnimated:YES completion:^{}];
}
However, the delegate method is not being called (breakpoint not hit, and NSLogs not being hit either).
Can someone help me out on why this is not working?
Thanks!
C
I think the following change should work. MFMessageComposeViewController is a UINavigationController subclass, so in your original code you are setting UINavigationControllerDelegate to self.
mcontr.messageComposeDelegate = self;

How can I alternate view controller and not lose data

I have two UIViewControllers, one is a UIPickerViewController, the Other a UITableViewController. Ideally the Picker should get a request from the user to add x amount of some item to the tableView. The Picker gets user inputs and assigns them to variables val1, val2, val3, where val1 is the number of items (number of rows) and val2 is the name or label for the item.
PickerViewController.m
- (IBAction)add:(id)sender
{
TableViewController *tvc = [[TableViewController alloc] init];
[tvc setValues:self.val1 :self.val2 :self.val3];
[self presentViewController:tvc animated:YES completion:nil];
}
TableViewController.m
-(void)setValues:(NSString *)newVal1 :(NSString *)newVal2 :(NSString *)newVal3
{
self.val1 = newVal1;
self.val2 = newVal2;
self.val3 = newVal3;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"UITableViewCell"];
// This is just a header which holds my "Add" button
UIView *header = self.headerView;
[self.tableView setTableHeaderView:header];
[self addNew:self.val1 :self.val2 :self.val3];
}
- (void)addNew:(NSString *)newVal1 :(NSString *)newVal2 :(NSString *)newVal3
{
if(!self.numberOfRows){
NSLog(#"Initially no of rows = %d", self.numberOfRows);
self.numberOfRows = [self.val1 intValue];
NSLog(#"Then no of rows = %d", self.numberOfRows);
}
else
{
self.numberOfRows = self.numberOfRows + [newVal1 intValue];
NSLog(#"New no rows = %d", self.numberOfRows);
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.numberOfRows inSection:0];
// Only run when called again .. not initially
if(self.run != 0){
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationBottom];
self.run ++;
[self.tableView endUpdates];
}
}
// "ADD" button which should go back to the picker and get new items to add to the table
- (IBAction)testAdd:(id)sender
{
PickerViewController *pvc = [[PickerViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
Now, I realize every time I call the next view controller I am creating a new instance of it, but I don't know how else to do it, I figure this is the main problem. As of right now, I expect when I leave the tableview for the picker view and return the console should log "New no of rows = x" but that doesn't happen.
I know val3 isn't used and my addNew: may not be the best, but I just need it to handle the basic logging mentioned above and I should be able to take it from there.
Been stuck on this for days
Create a property for TableViewController, and only create it the first time you present it,
- (IBAction)add:(id)sender {
if (! self.tvc) {
self.tvc = [[TableViewController alloc] init];
}
[self.tvc setValues:self.val1 :self.val2 :self.val3];
[self presentViewController:self.tvc animated:YES completion:nil];
}
It's not entirely clear from you question, whether it's this presentation or the one you have in the table view class that you're talking about. It also looks like you're doing something wrong in terms of presentation -- you're presenting the picker view from the table view controller, and also presenting the table view controller from the picker. That's not correct, you should present which ever controller you want to appear second, and that controller should use dismissViewControllerAnimated to go back, not present another controller.
In testAdd you don't need to create a new instance and present it. If you want to go back to the presentingViewController, just use dismissViewControllerAnimated .
And you will go one controller up in the stack.

Passing an float value to another ViewController

I have 2 controllers and i would like to send a float from LevelViewController to ViewController. But it always sends it as 0 (zero). Here is my LevelViewController.m
ViewController *inGame = [[ViewController alloc] init];
enemySpeedShouldBe = 0.800f - 0.07f * levelSelected;
inGame.enemySpeed = enemySpeedShouldBe;
Where levelSelected and enemySpeedShouldBe are also floats.
NSLog(#"%f", levelSelected) gives me the correct value (1.0, 2.0 etc.), but when I send it to ViewController, it's equal to 0.
Here is my ViewController.h
#property (nonatomic) float enemySpeed;
I've read about this issue but I couldn't find any way to make it work.
--/--/--/--/--/--/--/--/--/--/--EDIT--/--/--/--/--/--/--/--/--/--
here is my enemy millisecond counter methods in "ViewController.m"
-(void)enemyStartCounter{
enemyMs += 0.001;
if(enemyMs > enemySpeed){ // i use 'enemySpeed' nowhere except here
[enemyTimer invalidate];
[fire setHidden:YES];
[self enemyFired];
}
}
-(void)enemyCounter{
enemyMs = 0;
enemyTimer = [NSTimer scheduledTimerWithTimeInterval:0.001/1.0 target:self selector:#selector(enemyStartCounter) userInfo:nil repeats:YES];
}
and my button touchup inside action method in "LevelViewController.m"
- (void)didTapLevel:(UIButton *)buttonn{
levelSelected = (float)buttonn.tag + 1.0f ;
ViewController *inGame = [[ViewController alloc] init];
enemySpeedShouldBe = 0.800f - (0.07f * levelSelected);
inGame.enemySpeed = enemySpeedShouldBe;
[self performSegueWithIdentifier:#"1player" sender:self];
}
At some point in your code you are creating this instance of ViewController, configuring it with a value for enemySpeed, and then probably throwing it away.
Somewhere else, another instance is being created. This instance isn't configured, but you're calling enemyStartCounter on it, so it logs a zero.
You need to ensure that you understand what instances of each class you have and how they're being used. Your view controller could be created from a Storyboard segue, in this case you need to get a reference to it by intercepting the segue using prepareForSegue:sender:.
This code creates 2 different instances:
- (void)didTapLevel:(UIButton *)buttonn{
ViewController *inGame = [[ViewController alloc] init]; // create first instance
inGame.enemySpeed = enemySpeedShouldBe;
[self performSegueWithIdentifier:#"1player" sender:self]; // create second instance
}
So what you should be doing is:
- (void)didTapLevel:(UIButton *)buttonn{
[self performSegueWithIdentifier:#"1player" sender:self]; // create single instance
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ViewController *inGame = (ViewController *)[segue destinationViewController]; // get single instance
inGame.enemySpeed = enemySpeedShouldBe;
}
I prefer to create a NSNumber property to do this:
#property (strong, nonatomic) NSNumber *enemySpeed; // in your viewController
// passing the parameter
inGame.enemySpeed = [NSNumber numberWithFloat:(0.800f - 0.07f * levelSelected)];
Then if you pass the property between the controllers you can do this :
NSLog(#"%f", [enemySpeed floatValue]);

picker view value

I have a picker view in my first view controller.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent(NSInteger)component{
switch(row){
case 1:
isOne = true;
break;
case 2:
isTwo = true;
break;
case 3:
isThree = true;
break;
}
}
I want to read this boolean value in my second view controller. How should I do this?
thanks in advance
finally, I found the answer:
I just have to define a variable string in my first view controller as retain
#property (nonatomic, retain) NSString *aString;
in the implementaion file set:
#synthesize aString;
in the picker view method:
-(void)pickerView:(UIPickerView*)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
switch (row) {
case 0:
self.aString = [NSString stringWithString:#"One"];
break;
.....
}
do 1 & 2 in the seconde view controller. and set the selected value from picker view if you switch to the second controller:
SecondViewController * secController = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
secController.modalTransitionStyle = UIModalTransitionStyle;
[secController setAString:self.aString];
[self presentModalViewController:secController animated:YES];
I don't know if this is the best solution but it works for me right now.

Resources