I have a method "someMethod" declared in OneViewController.h
#interface OneViewController
{
UIView *tempView;
..
}
-(void) someMethod ;
#end
and implemented in OneViewController.m file
#implementation OneViewController
-(void) someMethod
{
tempView = [[UIView alloc]initWithFrame:CGRectMake(100, 50, 200, 250)];
tempView.backgroundColor = [UIColor yellowColor];
if([[self.view subviews] containsObject:tempView])
[tempView removeFromSuperView];
else
[self.view addsubview:tempView];
}
I want to call someMethod when present at different viewController - secondViewController
(something like [OneViewController someMethod]), So that when I get back to OneViewController I can see the changes made by someMethod.
Do I need to use appDelegate methods?
I have tried following but it doesn't work.
neViewController *newViewController = [[OneViewController alloc] init];
[newViewController someMethod];
Thanks for any help in advance..
In the SecondViewController, declare a reference for OneViewController class. You can have assign property. Set the reference before you move to SecondViewController. Now with the reference, you can call the instance method [_oneView someMethod].
Edit:
Declare
OneViewController *_oneView;
Also add the assign property,
#property(nonatomic,assign) OneViewController *_oneView;
Synthesize the variable in .m file.
While showing the SecondViewController from OneViewController, just add the following line.
secondView._oneView = self;
sometimes calling a method directlry creating [classObject methodName] does not refelect the changes in views. Like if you want to change a UIScrollView property from scrollEnble = NO; to scrollEnable = YES;, it does not refelect.
You should use singleton of UIApplication.
Suppose you want to call ViewController1's method - (void)myMethod in ViewController2 then here are the steps:
In you AppDelegate import ViewController1 and create its object *vc. Delare property #property (strong, nonatomic) ViewController1 *vc;. synthesize also.
Now come to Viewcontroller1 class. Import AppDelegate.h in you Viewcontroller1's and in viewDidLoad write like this:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.vc1 = self;
Go to your ViewController2.h and import AppDelegate.h
Go to the line where you want to call ViewController2's method and write like this:
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[[appDelegate vc1] myMethod]; // to allow scrolling
Ideally, you should create a protocol and delegate methods to accomplish what you are looking for.
Create a protocol, implement it in secondViewController and set the protocol delegate to firstViewController and then use the delegate methods for invoking the relevant methods in secondViewController
I hope it works for you..!!
One way of doing it is to change the declaration to +(void) someMethod ; in your OneViewController.h and change the minus to a plus correspondingly in the implementation file. This will make it a class-method and not an instance method. Then in your SecondViewController.m file, make sure to put #class OneViewController; before the implementation declaration; then you can call [OneViewController someMethod] and it should execute. Cheers!
Related
I'm working on an app and I need to pass data between view controllers. I know this is a common question but I couldn't find an answer for my problem : I'm able to pass data from the FirstViewController (MasterViewController in my case) to the SecondViewController (SettingsViewController) but not the reverse. What happens is that I call a method from the FirstViewController in my SecondViewController.m file. This works and it logs the data. But when I quit the SecondViewController (using [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];) the data is reset.
I tried using other methods to pass data but it didn't work. I'm using this code to pass data:
MasterViewController *vc = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[vc setPorts:SelectedPorts];
I also tried replacing [vc setPorts:SelectedPorts]; with vc.selectedCellIndexes = SelectedPorts; but the same problem occurs.
the setPorts method is declared in the FirstViewController.h file and SelectedPorts is a variable I declared in SecondViewController.m (it's not nil I checked).
Here's the setPorts: in FirstViewController.m :
- (void) setPorts:(id)selectedPorts {
selectedCellIndexes = selectedPorts;
NSLog(#"selectedCellIndexes : %#", selectedCellIndexes);
}
This logs the good value but when I log it in viewWillAppear in FirstViewController.m it's reset to the value it has before I called the method from SecondViewController.m.
Just to clarify, if I DON'T quit the SecondViewController.m, the data isn't reset.
I did read all your comments, and I really thanks you for your help. for convenience, I used a global variable.
Thanks for your help.
You have a list of ports in MasterViewController and you expect to use it in the SettingsViewController.
The MasterViewController can hold this list and SettingsViewController should have an access to it.
In SettingsViewController, have a setSelectedPort method:
#property (nonatomic, retain) id selectedPorts
- (void) setPorts:(id)selectedPorts;
The method saves the selected ports list into a property.
In MasterViewController, call the SettingsViewController and give it the list.
SettingsViewController *vc = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:nil];
[vc setSelectedPorts:yourValue];
When the list is modified inside the SettingsViewController, the list of ports contained in MasterViewController won't move even if you leave the SettingsViewController.
In secondViewController, You create protocol
#import <UIKit/UIKit.h>
#protocol sampleDelegate <NSObject>
- (void)passValue:(id)selectedPorts
#end
#interface SecondViewController : UIViewController
#property (nonatomic, strong) id <sampleDelegate> passDelegate;
#end
In viewDidLoad or wherever method as per your need, call method like this,
[self.passDelegate passValue:selectedPorts];
In FirstViewController.h,
Import the delegate <sampleDelegate>,
#import "SecondViewController.h"
#interface FirstViewController : UIViewController<SampleDelegate>
#end
In FirstViewController.m,
-(void)passValue:(id)selectedPorts
{
id receivedValues = selectedPorts;
}
and set self in your SecondViewController allocation,
SecondViewController *vc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
vc.passDelegate = self;
There is nothing unusual in the getting result. By doing
MasterViewController *vc = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
[vc setPorts:SelectedPorts];
You are creating a new instance of MasterViewController from your SecondViewController. This is not the same from which you navigated to the SecondViewController. So you wont get the expected result. Since you are setting the ports([vc setPorts:SelectedPorts]) to the newly created instance of the Master.
Instead of creating a new instance,just hold the reference of the MasterViewController in SecondViewController in a property and assign it before moving to second VC. As a beginner I suggested this way. But using delegate is the prefferred way passing data back.
Either use delegate methods to communicate with the master VC from the modal VC, or you could do something like this if you want to retrieive some manipulated objects from the modal VC.
Set the object(s) as properties in the modal view controller's .h-file (so they are public).
Using unwind segues, in the master VC, just do this:
-(IBAction)exitModalVC:(UIStoryboardSegue*)segue
{
SomeObject *obj = ((YourModalVC*)segue.sourceViewController).someObject;
//Do what you want with obj
}
EDIT:
This will only work if you are using unwind segue (which is a neat way of dismissing modal VC when using story board)
And you are using this, which is not unwind segues:
[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
You were creating a new instance of the first view controller from the 2nd view controller not accessing the same instance of the original caller. That was the reason why while you could see the logs but data were not there when you got back to the original caller - your MasterViewController.
You need to use delegate method. Check my answer for this SO.
This is problem related to object ownership.
Follow the below steps:
As per understanding you want reverse value from "SecondViewController" to "FirstViewController"
Don't create new object of FirstViewController in SecondViewController, it will not work.
Create object of "FirstViewController" in "SecondViewController.h" file.
#property (nonatomic,strong) FirstViewController *firstViewController;
When you navigate from FirstViewController to SecondViewController, please pass the "self".
e.g. SecondViewController *vc = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
vc.firstViewController = self;
If you want pass the reverse value to FirstViewController then in SecondViewController.m file.
[self.firstViewController setPorts:SelectedPorts];
And in FirstViewController.m refresh your controls with latest values.
Try above code will defiantly work as per your requirement.
So I tried this in many different ways but I can't get it to work. Im trying to change the state of a UIbutton in a different class.
class1.h
#property (strong, nonatomic) IBOutlet UIButton *monthly;
class2.m
- (void)viewDidLoad
{
ViewController *vc = [[ViewController alloc] init];
vc.monthly.enabled = NO;
}
Whatever I try and where ever I put the code, the button state is not changing. When I log the state in class2.m:
NSLog(vc.monthly.enabled ? #"Yes" : #"No");
It always returns No, even if I just stated it as YES in my class2.m. Long story short: My button property is not updating from a different class. Please tell me if you need to see any more code and i'll update asap.
i think problem is with class instance. the following line create new instance
ViewController *vc = [[ViewController alloc] init];
that's why your button state is not changing you have to get reference of your previously created intstace no need to create new instance.
for this you can use AppDelegate file to declare property of class1.
see following code
AppDelegate.h
#Property(nonatomic, ratain) ViewController *vc;
AppDelegate.m
#synthesize vc;
now alloc & initialize vc whenever you need it like following.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication
sharedApplication] delegate];
appDelegate.vc=[[ViewController alloc] init];
also don't forgot to import AppDelegate.h file where you write above code.
now using appDelegate.vc you can use all property of View Controller in all classes of you project.
The main problem is you are creating new instance each time when you are going to check the button state. But the button state is for the button which you have created in class1.h. So you have need that you should create button in Appdelegate class and fetch the instance from Appdelegate in the class where you are checking the status of button and check the status of button. I think it will help.
Access the button using the object of the ViewController class that is already in the stack. No need to creat a new object like ViewController *vc = [[ViewController alloc] init];. When you are doing this it creates a new object so you are not getting the write thing.
I am creating a code in which i want to pass integer value for one uiview to another view.In another uiview that integer value so as text of label.How make code for that?
Take this in .h file in SecondViewController
int value;
Make below function in SecondViewController
-(void)setValue:(int)number{
value=number;
}
Now In First view controller do like this:
ParentViewController *objSecond = [[ParentViewController] initwithNibName:#"parentView.xib" bundle:nil];
[objSecond setValue:15]; // Pass actual Value here
[self.navigationController pushViewController:objSecond animated:YES];
[objSecond release];
Now, In secondViewController viewWillAppear Method write this.
-(void)viewWillAppear:(BOOL)animated{
myValue = value;
}
Please check spelling mistakes as I hand written this. Hope this help.
If you are not using navigationContoller then you can do something like this.
SecondViewControler *objSecond = [[SecondViewController] initwithNibName:#"secondview.xib" bundle:nil];
[objSecond setValue:15]; // Pass actual Value here
[objSecond viewWillAppear:YES];
[self.view addSubview:objSecond];
[objSecond release];
You can pass it as integer value itself as u do in c or in any other language.
In the second view, u can convert it to string with [NSString stringWithFormat:#"%d",intVal];
In second view, declare a NSUInteger variable , say NSUInteger _intVal.
In .h file, declare a method like
-(void)setIntVal:(NSUInteger)inVal;
In .m file,
-(void)setIntVal:(NSUInteger)inVal
{
_intVal = inVal;
}
Now u can use the _intVal in the second view.
declare a varable in .h file
NSInteger tempValue;
declare a method like that:
- (void)SetValue:(NSInteger)value {
tempValue=value;
}
- (void)GetValue{
return tempValue;
}
when you set it, you use:
AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[app SetValue:xxxx]
when you need it, use:
AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
xxxx = [app GetValue];
When you are going from view1 to view2 then do like this.
Take one variable in view2 and set the property as
#property (nonatomic,readwrite) int val; //this is in the view2 .h file
in view2 .m file do this. #synthesize val;
Then when you are adding the view2 as subview to view1 then
view2object.val=someval;// like 1,2,3....
I have two view controllers, firstViewController and secondViewController. I am using this code to switch to my secondViewController (I am also passing a string to it):
secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];
second.myString = #"This text is passed from firstViewController!";
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];
I then use this code in secondViewController to switch back to the firstViewController:
[self dismissModalViewControllerAnimated:YES];
All of this works fine. My question is, how would I pass data to the firstViewController? I would like to pass a different string into the firstViewController from the secondViewController.
You need to use delegate protocols... Here's how to do it:
Declare a protocol in your secondViewController's header file. It should look like this:
#import <UIKit/UIKit.h>
#protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
#end
#interface SecondViewController : UIViewController
{
id myDelegate;
}
#property (nonatomic, assign) id<SecondDelegate> myDelegate;
Don't forget to synthesize the myDelegate in your implementation (SecondViewController.m) file:
#synthesize myDelegate;
In your FirstViewController's header file subscribe to the SecondDelegate protocol by doing this:
#import "SecondViewController.h"
#interface FirstViewController:UIViewController <SecondDelegate>
Now when you instantiate SecondViewController in FirstViewController you should do the following:
// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = #"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];
Lastly, in the implementation file for your first view controller (FirstViewController.m) implement the SecondDelegate's method for secondViewControllerDismissed:
- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}
Now when you're about to dismiss the second view controller you want to invoke the method implemented in the first view controller. This part is simple. All you do is, in your second view controller, add some code before the dismiss code:
if([self.myDelegate respondsToSelector:#selector(secondViewControllerDismissed:)])
{
[self.myDelegate secondViewControllerDismissed:#"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];
Delegate protocols are EXTREMELY, EXTREMELY, EXTREMELY useful. It would do you good to familiarize yourself with them :)
NSNotifications are another way to do this, but as a best practice, I prefer using it when I want to communicate across multiple viewControllers or objects. Here's an answer I posted earlier if you're curious about using NSNotifications: Firing events accross multiple viewcontrollers from a thread in the appdelegate
EDIT:
If you want to pass multiple arguments, the code before dismiss looks like this:
if([self.myDelegate respondsToSelector:#selector(secondViewControllerDismissed:argument2:argument3:)])
{
[self.myDelegate secondViewControllerDismissed:#"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];
This means that your SecondDelegate method implementation inside your firstViewController will now look like:
- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
NSString thisIsTheDesiredString = stringForFirst;
NSObject desiredObject1 = inObject1;
//....and so on
}
I could be way out of place here, but I am starting to much prefer the block syntax to the very verbose delegate/protocol approach. If you make vc2 from vc1, have a property on vc2 that you can set from vc1 that is a block!
#property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);
Then, when something happens in vc2 that you want to tell vc1 about, just execute the block that you defined in vc1!
self.somethingHappenedInVC2(#"Hello!");
This allows you to send data from vc2 back to vc1. Just like magic. IMO, this is a lot easier/cleaner than protocols. Blocks are awesome and need to be embraced as much as possible.
EDIT - Improved example
Let's say we have a mainVC that we want to present a modalVC on top of temporarily to get some input from a user. In order to present that modalVC from mainVC, we need to alloc/init it inside of mainVC. Pretty basic stuff. Well when we make this modalVC object, we can also set a block property on it that allows us to easily communicate between both vc objects. So let's take the example from above and put the follwing property in the .h file of modalVC:
#property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);
Then, in our mainVC, after we have alloc/init'd a new modalVC object, you set the block property of modalVC like this:
ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
NSLog(#"Something was selected in the modalVC, and this is what it was:%#", response);
}
So we are just setting the block property, and defining what happens when that block is executed.
Finally, in our modalVC, we could have a tableViewController that is backed by a dataSource array of strings. Once a row selection is made, we could do something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedString = self.dataSource[indexPath.row];
self.somethingHappenedInModalVC(selectedString);
}
And of course, each time we select a row in modalVC, we are going to get a console output from our NSLog line back in mainVC. Hope that helps!
hmm, look for the notification centre and pass back info in a notification. here is apples take on it
- I take this approach personally unless any one has any other suggestions
Define a delegate protocol in the second view controller and make the first one the delegate of the second.
In my subclass of NSObject I would like to call something like
[[self navController] presentModalViewController:myView animated:YES];
But none of my tries were successful. How can I call a modal view if I'm not in a subclass of UIViewController?
Solution:
#import "myProjectNameAppDelegate.h"
// ...
MyViewController *myView = [[MyViewController alloc] init];
myProjectNameAppDelegate *appDelegate = (myProjectNameAppDelegate *)[[UIApplication sharedApplication] delegate];
[[appDelegate navController] presentModalViewController:myView animated:YES];
better way to call a presentModalViewController is, passing viewcontroller to the NSobject class. call the nsobject function from the uiviewcontroller
Here is the code with mail example
In view Controller //your current view
[nsobjectclassObject OpenMailComposer:self]; //this will take the viewcontroller to NSobject class
In NSObject class //may be sharing class
-(void)OpenMailComposer:(UIViewController*)view
{
viewControllertoShow = view; // viewControllertoShow is UIVIewcontroller object
MFMailComposeViewController *mailView = [[MFMailComposeViewController alloc]init];
mailView.mailComposeDelegate = self;
[mailView setSubject:#"Hey! check this out!"];
[viewControllertoShow presentModalViewController:mailView animated:YES];
}
For dismissing from NSObject class you can do the following
[viewControllertoShow dismissViewControllerAnimated:YES]
I don't see a way to display a modal view without a ViewController. You have to store a reference to a UIViewController in your class so you can access it. Or setup a property in your AppDelegate, which you can get by calling [[UIApplication sharedApplication] delegate];
If you hold the navigationController or some viewController, you can present a modal view controller.
What is your myView? Is it a view, is it a viewController. I hope that it is a viewcontroller otherwise, this is the reason your code doesn't run