This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I have a multiple view application and in ViewController I have added some code that I would like to be able to access from ViewController2. The purpose of the code being accessible in ViewController2 is so I can have it run in there as well as in ViewController. I have already imported the ViewController.h file into ViewController2 but I am unsure of how to share the data between controllers. The code is as follows:
ViewController2.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"
#interface ViewController2 : UIViewController
#property(nonatomic, readonly) NSUInteger tapCount;
#property NSInteger numberOfLoops;
#property(readonly) NSTimeInterval deviceCurrentTime;
#property (strong, nonatomic) AVAudioPlayer *myPlayer;
- (NSTimeInterval)timeIntervalSinceDate:dateTimePicker;
- (BOOL)playAtTime:(NSTimeInterval)time;
- (IBAction)iconsBtn:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#import <AVFoundation/AVFoundation.h>
#import "ViewController.h"
#interface ViewController2 ()
{
AVAudioPlayer *_myPlayer;
}
#end
#implementation ViewController2
- (void)viewDidLoad { //This is where I want to use the data
[super viewDidLoad];
}
ViewController.h
#import <UIKit/UIKit.h>
#import <AvFoundation/AVFoundation.h>
ViewController.m
#import "ViewController.h"
How should I do so? It is most important that I can use the one particular string in ViewController.m
Thanks
EDIT
This is different from the other one because I was asking specifically how to do something where as the answers for the other one were more general and I was asking specifically how to share one object not multiple objects.
U can use segues for transferring data between viewcontrollers.
check this link for more details
First of all, u need to declare your dateTimeString as a property in your .h file (ViewController.h)
Then you can call the segue using
[self performSegueWithIdentifier:#"your_segue_identifier_name" sender:self];
Then
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"your_segue_identifier_name"])
{
}
}
If you want to use a property (dateTimeString) from a presented view controller i would go with delegation.
Related
First, sorry for this question, but I am new on iOS development, and i am stuck on this all afternoon, I'm trying to change the value of a int variable using one slider located in a another viewController.
The slider of the row is located in a modal window inside the view, i think that this is the problem, but i don't know.
This is the code:
#interface ViewController ()
#property int row, column, actualGame;
#end
- (IBAction)rowChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int val = slider.value;
[self setRow: val];
self.rowLabel.text = [NSString stringWithFormat:#"%d",val];
}
- (IBAction)columnChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int val = slider.value;
_column = val;
self.collumLabel.text = [NSString stringWithFormat:#"%d",val];
}
In order to pass data between view controllers, there are a couple of different options available to you. The simplest would be to just store a reference to the first view controller on your second view controller. You can set the property in the `prepareForSegue' method of your first view controller.
FirstViewController.h (the view controller that's presenting the modal VC):
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
#property (nonatomic) float sliderValue;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "ViewController.h"
#implementation FirstViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"mySegueDefinedInStoryboard"]) {
ViewController *destinationViewController = (ViewController *)segue.destinationViewController;
destinationViewController.firstViewController = self;
}
}
#end
ViewController.h (the modal view controller):
#import <UIKit/UIKit.h>
#class FirstViewController;
#interface ViewController : UITableViewController
#property (nonatomic, weak) FirstViewController *firstViewController;
#end
ViewController.m
#import "ViewController.h"
#import "FirstViewController.h"
#implementation ViewController
- (IBAction)columnChanged:(UISlider *)sender {
float value = sender.value;
self.firstViewController.sliderValue = value;
}
#end
The downside of this method is that it creates tightly coupled code - ViewController needs to know about FirstViewController, which isn't optimal. Once you get a little bit more practiced, you'll learn about creating your own delegate, so that you can send messages to other view controllers without caring what their class is or what their properties are.
Apple Documentation on the Delegate Pattern
i have two view controllers, AbcViewController and XyzViewController. Both controllers behave similarly. Each has a "add" button which opens up a AddNewAbcViewController and AddNewXyzViewController respectively.
On AddNewAbcViewController, when the button "submit" is taped, it does it necessary stuff and close, bringing it back to AbcViewController. I am using delegate here where AbcViewController does the closing of AddNewAbcViewController. This works.
Now I want to do the same for XyzViewController and AddNewXyzViewController, but it is not working. When the btnSubmit is called in AddNewXyzViewController, it didn't enter into XyzViewController dimiss method. I have scanned through my codes many times but don't find anything extra not added. I even gave a different dismiss method name in XyzViewController and AddNewXyzViewController but that didn't work either. What did I miss?
here are my snippets for AbcViewController and AddAbcViewController. The codes for Xyz are identical:
class AddNewAbcViewController.h is
#import <Foundation/Foundation.h>
// protocol
#protocol AddNewAbcProtocol <NSObject>
-(void)dismiss;
#end
#interface AddNewAbcViewController : UIViewController<UITextViewDelegate>
#property(nonatomic, weak)id<AddNewAbcProtocol> delegate;
#end
class AddNewAbcViewController.m is
#interface AddNewAbcViewController() <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
...
#end
#implementation AddNewAbcViewController
...
- (IBAction)btnSubmit:(id)sender
{
[self.delegate dismiss];
}
#end
class AbcViewController.h is
#import <Foundation/Foundation.h>
#import "AddNewAbcViewController.h"
#interface AbcViewController : UIViewController<AddNewAbcProtocol, UISplitViewControllerDelegate>
...
#end
class AbcViewController.m is
#implementation AbcViewController
-(void)dismiss
{
NSLog(#"delegated to dismiss()");
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
As everyone explained, basically you forgot a line of code like ".delegate = self".
Here's a handy beginner's intro to delegates.
https://stackoverflow.com/a/4213005/294884
Use if statement to see if delegate works:
if ([self.delegate respondsToSelector:#selector(dismiss)])
{
[self.delegate dismiss];
}
Create AddNewXyzViewController as an instance variable, but not a local variable.
I followed the advice at this link Changing the value of a property of another UIViewController
I have a Login page that is connected to a github project that I downloaded called SWRevealViewController. It essentially provides a slide out menu for the application. I need to pass a value from my Login Page to the initial Page that is loaded with the SWRevealViewController. Can't seem to get it working. Can anyone point me in the right direction? What I have tried is the following:
LoginViewController.m
#import "LoginViewController.h"
#import "ProfileTableViewController.h"
#interface LoginViewController ()
#property (strong, nonatomic) ProfileTableViewController *secondViewController;
#end
#implementation dbViewController
-(id)init
{
if (self = [super init]) {
self.secondViewController = [[ProfileTableViewController alloc] init];
}
return self;
}
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if([identifier isEqualToString:#"Login"]){
[self login:sender];
self.secondViewController.idNumber = _IDNumber;
_secondViewController.idNumber = _IDNumber;
return YES;
}
}
LoginViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "ProfileTableViewController.h"
#interface LoginViewController : UIViewController
#property (strong, nonatomic)NSString *IDNumber;
#end
ProfileTableViewController.h
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#interface ProfileTableViewController : UIViewController <CLLocationManagerDelegate, UITextFieldDelegate>
#property (nonatomic) NSString *idNumber;
#end
ProfileTableViewController.m
#import "ProfileTableViewController.h"
#import "SWRevealViewController.h"
#import "ProfileEditFieldController.h"
#interface ProfileTableViewController ()
#end
#implementation ProfileTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(_idNumber);
}
#end
Just to add clarification, the two blue controllers are the Login, and the three controllers on the right, one of them is the controller I would like to pass the value for
You should do it like this instead:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ProfileTableViewController *pvc = (ProfileTableViewController*)[segue destinationViewController];
pvc.idNumber = _IDNumber
}
Hope that works! :)
UPDATE:
I think what you need is NSUserDefaults, use it, and store the ID. You gonna need it in more than one controller I believe, and its easy to store data on.
NSUserDefaults
It's not 100% clear from what you've shown but I'm assuming that these view controllers are defined in a storyboard and that the "Login" segue is also defined in the storyboard and causes a transition from LoginViewController to ProfileTableViewController.
One thing I am confused about is why the #implementation line in LoginViewController.m says "dbViewController" but I'm assuming that's a typo and that it should be "#implementation LoginViewController".
So, assuming all of that is true, there are a couple of problems in your code. First, you shouldn't be creating the ProfileTableViewController in LoginViewController's init method. iOS will automatically alloc and init the ProfileTableViewController when the segue is performed.
Second, instead of using shouldPerformSegueWithIdentifier:sender:, you want to use prepareForSegue:sender:. When that method is called, iOS will have already created the ProfileTableViewController and you can set your property.
So, what you want is something like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"Login"])
{
ProfileTableViewController * viewController = segue.destinationViewController;
viewController.idNumber = _IDNumber;
}
}
I have made a simple app to test this and cannot figure it out. I have an iPad storyboard where I have put two container views as shown below. I have a label in one view and a button in another. My button will increment the label, 1 number at a time.
My problem is not passing the value or incrementing, but getting the view to load the new value.
Each container has its own ViewController
Some code below, although very sparse as Ive written a bunch and deleted as it didn't work. Please help with the correct format. I would like to keep this general format, updating global variable within button and it updating the label.
LabelViewController.h
#import <UIKit/UIKit.h>
#interface LabelViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *checkLabel;
-(void)loadLabel;
#end
LabelViewController.m
#import "LabelViewController.h"
#import "ParentViewController.h"
#interface LabelViewController ()
#end
#implementation LabelViewController
#synthesize checkLabel;
-(void)loadLabel{
checkLabel.text = [NSString stringWithFormat:#"%d",value];
[self.view setNeedsDisplay];
}
- (void)viewDidLoad
{
[self loadLabel];
[super viewDidLoad];
}
ButtonViewController.h
#import <UIKit/UIKit.h>
#interface ButtonViewController : UIViewController
- (IBAction)checkButton:(id)sender;
#end
ButtonViewController.m
#import "ButtonViewController.h"
#import "ParentViewController.h"
#import "LabelViewController.h"
#interface ButtonViewController ()
#end
#implementation ButtonViewController
- (IBAction)checkButton:(id)sender {
value++;
NSLog(#"%d",value);
LabelViewController *fnc = [[LabelViewController alloc] init];
[fnc loadLabel];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
Picture at:
http://farm4.staticflickr.com/3822/9469907420_746db25b23_b.jpg
In ButtonViewController, you don't want to be alloc init'ing an instance of LabelViewController -- the one that's on screen already exists. Both child view controllers are instantiated just before the parent controller is. So, what you need to do is get a reference to the LabelViewController that's on screen. You can do that with self.parentViewController.childViewControllers[0] (that 0 might have to be 1 -- I don't know which controller is which).
LabelViewController *fnc = self.parentViewController.childViewControllers[0];
[fnc loadLabel];
I have masterViewController and detailViewController. Masterview pushes detailView. When going back to masteViewController I want to update the foo value. But I only get NULL from nslog. How can I set the parenteViewContrller.foo value to #"bar" when navigationback?
masterViewController.h
NSString *foo;
-(void)setFoo:(NSString *)fooValue
#property(nonatomic, retain) NSString *foo;
masterViewController.m
#synthesize foo;
-(void)setFoo:(NSString *)fooValue{
NSLog(#"updated foo:%#", fooValue);
}
detailViewController.m
-(void)goBack{
[self.navigationController.parentViewController setValue:#"bar" forKey:#"foo"];
[self.navigationController popViewControllerAnimated:YES];
}
[UIViewController parentViewController] will not return what you are expecting from iOS 5 onward, instead you should be using [UIViewController presentingViewController]
If you are just targeting iOS 5, it is easy enough to start using presentingViewController instead, but if not I would advise that you manually pass your UIViewController on:
// DetailViewController.h
#class MasterViewController;
#interface DetailViewController : UIViewController
#property (assign, nonatomic) MasterViewController *masterViewController;
#end
// DetailViewController.m
#import "DetailViewController.h"
#import "MasterViewController.h"
#implementation DetailViewController
- (void)goBack {
[self.masterViewController setFoo:#"bar"];
// dismiss this view controller
}
#end
// MasterViewController.h
#interface MasterViewController : UIViewController
- (void)setFoo:(NSString *)bar;
#end
// MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#implementation MasterViewController
- (void)goForward {
DetailViewController *detailViewController = ...;
[detailViewController setMasterViewController:self];
// present this view controller
}
#end
In order for setValue:ForKey: to work, your view controller must conform to NSKeyValueCoding protocol.
Try this:
-(void)goBack{
[self.navigationController.parentViewController setFoo:#"bar"];
[self.navigationController popViewControllerAnimated:YES];
}
and don't forget to retain/release appropriately in your setFoo: method. You probably also need to type cast parentViewController to avoid any warnings.
Pass the reference of the master with assign property to detail view.
Using this reference set the foo value before performing pop action.
gIf you want to pass a object to the parent you could try creating an external object in a header file and importing the header in the controller where you want to use it however THIS IS NOT BEST PRACTICE but it's a quick fix
import
extern MyObject* Object;
#interface GlobalVariables : NSObject {
}
#end
All you have to do now is include the header in the controllers and use the global variable.
If you want to do it by the books i suggest you create a delegate that handles the object passing.
Normally, under this scenario, you need to use delegate. Check out my answer to this similar question in this SO.