How to call function from one viewcontroller to another controller? - ios

SettingsStore.h
#interface SettingsStore : IASKAbstractSettingsStore
{
#public
NSDictionary *dict;
NSDictionary *changedDict;
}
- (void)removeAccount;
#end
menuView.m
-(IBAction)onSignOutClick:(id)sender
{
SettingsStore *foo = [[SettingsStore alloc]init];
[foo removeAccount];
[self.navigationController pushViewController:foo animated:YES];
exit(0);
}
I want to call this removeAccount function from menuView.m. But I am getting error.
How to fix it and call this removeAccount.

There are few mistakes in your Code please find them below.
[foo removeAccount]; Calling this method is correct
[self.navigationController pushViewController:foo animated:YES];
Not correct because SettingsStore is not subclass of
UIViewController only subclass of UIViewController can be pushed to
Navigation controller
exit(0); Calling this method is not
recommended by Apple

You are calling removeAccount correctly from your menuView.m file, but there are several issues with your code:
You are treating foo as though it were a UIViewController, and it's actually a member of the SettingStore class. Does the SettingStore class refer to an actual screen, or is it more a data object (for storing settings?). If it's the latter, you don't want to push it on. You can create it, and use it, but the user doesn't need to see it.
You are calling exit(0); you can remove that line. If you want to remove the menuView.m file from your memory, remove references to it (e.g. from its parent view controller).
The menuView.m file is confusing, as in, is it a view or a viewController. An IBAction I would normally stick in a ViewController file, rather than a view file. Your basic design pattern is MVC (Model / View / Controller). In this case, it seems your SettingStore file is a Model (data), the menuView.m is a View and your code is for the Controller bit.

Related

Pass data between two ViewControllers [duplicate]

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];
}

Call method for different UIViewController

I am making master detail application, i have dynamic Detail ViewController. Detail ViewController are changed.
But in every Detail ViewController I have one common method updateInfo I want to call that method
Here is my code
UINavigationController *nav=[self.splitViewController.viewControllers objectAtIndex:1];
UIViewController *controller=[nav.viewControllers objectAtIndex:0];
[controller updateLastInfo];
But it gives me error no method found.
it will work if i use UIViewController name.
HomeViewController *controller=(HomeViewController)[nav.viewControllers objectAtIndex:0];
[controller updateLastInfo];
But i dnt want to do above things.
I have tried to explain. Please help
You can use id
UINavigationController *nav=[self.splitViewController.viewControllers objectAtIndex:1];
id controller=[nav.viewControllers objectAtIndex:0];
[controller updateLastInfo];
You could subclass UIViewController and make a base DetailViewController class that houses common functionality of your detail view controllers. Then you would make all of your detail view controllers subclass DetailViewController instead of UIViewController. This would be a safe way to do it and would also allow you to add extra functionality to your updateInfo method in the specific detail view controllers.
If you want an unsafe way, you could make your controller object of type id. I wouldn't suggest this approach as it relies on your personal knowledge of the code. If someone else (or yourself down the road) sets it to a view controller that doesn't have that method, the code will still try to run and will crash.
UIViewController doesn't have a method named updateInfo, so the compiler will of course complain when you try to send that message to a pointer that's known only to point to an instance of UIViewController. When you use the class name, like this:
HomeViewController *controller=(HomeViewController)[nav.viewControllers objectAtIndex:0];
you're providing more information to the compiler, using a type cast to tell it "Hey, don't worry, I know for certain that the object I'll get back is a HomeViewController. Since you seem to have several types of view controllers that all have this method, the best thing to do is to declare the updateInfo method in a protocol and then have each of those UIViewController subclasses implement that protocol. So, your protocol declaration would be in a header file and might look like:
#protocol SomeProtocol
- (void)updateInfo
#end
and each class that has an -updateInfo method would just need to declare that it adopts the protocol:
#interface HomeViewController <SomeProtocol>
//...
#end
and then make sure that you have an -updateInfo in your class implementation:
#implementation HomeViewController
- (void)updateInfo {
//...
}
//...
#end
Then, in your code, you can either check that the object conforms to the protocol using -conformsToProtocol: like this:
if ([controller conformsToProtocol:#protocol(SomeProtocol)]) {
UIViewController<SomeProtocol> *c = (UIViewController<SomeProtocol>*)controller;
[c updateInfo];
}
or else just check that the object responds to the selector before calling it:
if ([controller respondsToSelector:#selector(updateInfo)]) {
[controller performSelector(updateInfo)];
}
The other answers you've received (using id or creating a common base class) are also good ones, but to be safe make sure you do some checking before calling your method. For example, you can use -isKindOfClass to make sure that the view controller you get back is in fact an instance of your common base class, and you can use -respondsToSelector: as above to check that an id points to an object that implements updateInfo.

Array + UIView Controller + UITableViewController

I have a UIViewController class and a UITableViewController class. Within the UIViewController class I have an NSMutableArray.
I now have the issue of how to load data into my table view, a separate class, I must access the NSMutableArray I used to populate the previous UIViewController class.
I tried using a delegate to access the array in the UIViewControllerClass however the array had "0 objects" and was NULL
I would appreciate some guidance in the right direction here.
You could have one view controller hold a reference to the other view controller and query the public NSMutableArray on it for data. Aaron suggested this and it might be your best solution.
Or.. you have multiple view controllers trying to access the same set of data. Potentially you have other classes which will want to access this data also. You might want to consider pulling the data out of the view controller and storying it in a neutral location. You could store it in the AppDelegate and then reference the app delegates from any place you need it.
id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
NSMutableArray *myData = appDelegate.data;
You could also consider pulling all the logic of your data and the data itself into a separate class and use a Singleton It would allow you to access/manipulate the data fairly easy from anywhere.
The last 2 methods would insulate data from user interface controller objects and prevent the need from potentially unrelated objects needing to hold references to one another. Used properly it will reduce code complexity and mage future changes easier to manage.
Create an NSMutableArray property on your UITableViewController class like so:
#interface CustomTableViewController : UITableViewController
#property (strong, nonatomic) NSMutableArray *dataFromOtherClass;
#end
And then when you transition, perhaps like this, you can set the dataFromOtherClass property:
CustomTableViewController *controller = [[CustomTableViewController alloc] initWithNibName:#"CustomTableViewController" bundle:nil];
controller.dataFromOtherClass = myNSMutableArrayData; // <-- Set data like this
[self.navigationController controller animated:YES];
// Or ...
[self presentViewController:controller animated:YES];
// Etc...

Communiacting between UIDatePicker and UITableView

In my project I have 3 controllers;
NavigationController
ServiceTableViewController
DateTableViewController
The ServiceTableViewController is the initial view controller. It has several rows which prompt the user to enter in data, which will be emailed to a particular email address. One of the rows, when tapped, sends the user to the DateTableViewController which prompts the user to select a date from the UIDatePicker.
The issue I am facing is getting data back from DateTableViewController in order to display a label on the ServiceTableViewController to show the date the user selects in the DateTableViewController. I know how to get information from one view controller to another, but to go in reverse, so to speak, is not something I know how to do. Any help is appreciated.
Take a look at this:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html
There are couple of ways to pass data back and forth between view controllers.
Delegates
Target-Aciton
Notification
KVO
but honestly delegates are really all you need really and it sounds like in your current case.
see this -> (Passing Data between View Controllers)
Having said that, if you use delegates, here is how ---
setup a protocol in DateTableViewController.h at the top like so:
#protocol DateTableViewControllerDelegate <NSObject>
- (void)userSelectedThisDate:(NSDate *)d;
end
put this with the other properties
#property (nonatomic, weak) id <DateTableViewControllerDelegate> delegate;
and in DateTableViewController.m with the date to send back
[self.delegate userSelectedThisDate:withTheDateToSendBack];
in and ServiceTableViewController.h add
#import "DateTableViewController.h"
#interface ServiceTableViewController : UIViewController <DateTableViewControllerDelegate>
and since you are UINavigationController, somewhere in ServiceTableViewController.m add this when you are about to push to the DateTableViewController
DateTableViewController *vc = [[DateTableViewController alloc] init];
self.delegate = self;
[self.navigationController pushViewController:vc animated:YES];
and finally put the delegate method in ServiceTableViewController.m
- (void)userSelectedThisDate:(NSDate *)d {
NSLog(#"%#", d); // this should show the returned date
}
Research delegate pattern (here) (a heavily used pattern within Apple frameworks). You want to define a delegate protocol which allows to a date to be passed to the delegate.
You could implement the pattern as an #protocol with a single method and a property on the DateTableViewController. The ServiceTableViewController sets itself as the delegate before pushing the DateTableViewController.
Or, you could implement using a block. Again, the ServiceTableViewController sets the block before pushing the DateTableViewController.

Help using a view controllers methods before the view is loaded

I have a UIViewController called DebugViewController that contains a UITextView, and a public method called debugPrint which is used to write an NSString into the UITextView and display it.
Is it possible to write into the UITextView before I open the UIViewController, so that when I open it, the text previously written into it is displayed?
In my parent view controllers viewDidLoad method, I'm calling initWithNibName on the DebugViewController as follows
debugViewController = [[DebugViewController alloc] initWithNibName:#"DebugView" bundle:nil];
I then call debugPrint as follows
[debugViewController debugPrint:#"viewDidLoad"];
And some time later I call the following to open the debugViewController
debugViewController.delegate = self;
debugViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:debugViewController animated:YES];
However all the text previously written is missing.
Please let me know how I can use a view controllers methods before the view controller displayed to the user.
Thanks,
JustinP
What you are doing is a little non-standard. The danger with that as always is that if you don't really have an expert grasp on what you're doing, you can quickly find yourself in difficulty.
If you want something set before the view is displayed to the user, then the best way to do that is to do it in the viewWillAppear method. Put it there rather than in viewDidLoad because a view might loaded once but appear many times. Where you place it depends on whether the data changes from appearance to appearance.
So, if your data is pretty static and won't change, use the viewDidLoad method.
Assuming that you'll go for the viewWillAppear option, let's do the first step by having an ivar in the view controller:
NSString *myText;
set that after init:
debugViewController = [[DebugViewController alloc] initWithNibName:#"DebugView" bundle:nil];
debugViewController.myText = #"My text here";
then, in debugViewController's viewWillAppear method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
myTextView.text = myText;
}
The view controller life cycle is complex as you can see from the View Controller Programming Guide for iOS. So I'd say best not stray from the path of least resistance unless you have good reason. That said sometimes the best way to learn is by experimentation.

Resources