Reputation: 145
I have two view controllers, call them viewA
and ViewB
ViewA
ViewB
, all is well and the menu comes upNow, the user touches one IBAction
button, which programmatically just needs to:
BOOL
, call it myBOOL
to YES
ViewB
myBOOL
variables current state of YES
back to ViewA
I have declared the same BOOL
, set property, synthesized on both Views, but per my NSLog
upon dismissal of ViewB
and loading back up ViewA
, it reverts back to NO
So I know I'm going off on a tangent, I just want to know if you can send the value of a BOOL
between two controllers and if so, please show me an example... as searches have found Protocols and Delegate examples with NSString
's, and when I attempt with a BOOL
I get stuck in an import loop, however I've read that its possible to make a global BOOL
, as bad design as it is, I just need to get over this block for now.
Upvotes: 0
Views: 4297
Reputation: 5107
There are two options available storing and retrieving data in different view controllers.
1)NSUserDefaults
is best option for storing data and accessing in any other view controllers.
The NSUserDefaults
class provides convenience methods for accessing common types such as float, double, integer, Boolean
.
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary
.
This is very easy and best method for storing and retrieving data.
if you want to read about NSUserDefaults
, here I am sharing document.
[NsuserDefaults Document.][1]
2) You would create properties when you want them to be accessible outside the class or other view controllers.
Create property in this way. @property (nonatomic, retain) NSArray *arrayData;
and then you can use this array value in other view controllers also.
Properties replace the accessor methods for objects.
Upvotes: 1
Reputation: 5107
There are two options available storing and retrieving data in different view controllers.
1)NSUserDefaults
is best option for storing data and accessing in any other view controllers.
The NSUserDefaults
class provides convenience methods for accessing common types such as float, double, integer, Boolean
.
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary
.
This is very easy and best method for storing and retrieving data.
if you want to read about NSUserDefaults
, here I am sharing document.
NsuserDefaults Document.
2) You would create properties when you want them to be accessible outside the class or other view controllers.
Create property in this way. @property (nonatomic, retain) NSArray *arrayData;
and then you can use this array value in other view controllers also.
Properties replace the accessor methods for objects.
You can see my answer here. Pass value from one view controller to another
Upvotes: 1
Reputation: 1652
I think best way to use powerful features of blocks in below ways.
In ViewB.h
typedef void (^CompletionHandler)(BOOL myBool);
@interface ViewB : UIViewController {
CompletionHandler completionHandler;
}
- (void)dismissHandler:(CompletionHandler)handler;
In ViewB.m
- (void)dismissHandler:(CompletionHandler)handler {
completionHandler = handler;
}
- (IBAction)dismiss:(id)sender {
completionHandler (YES); // your yes no logic here
}
In ViewA.m
- (IBAction)showPopup:(id)sender {
ViewB *vc = [[ViewB alloc] init];
[self.view addSubview:vc.view];
[vc dismissHandler:^(BOOL myBool) {
if (myBool) {
//Do your work;
}
}];
}
Upvotes: 0
Reputation: 2224
You don't need to use NSNotificationCenter, NSUserDefaults or global variables.
As long as the view controllers are related (and looking at the OP's question, they certainly seem to be) you can simply set the view controllers up to hold a reference to each another (with one of the references being weak of course in order to avoid a "retain", or "strong reference", cycle). Then each view controller can set the property on the other view controller as needed. Example follows...
NB: This concept is valid for any two related view controllers. However, the following code assumes that:
FirstViewController.h
@interface FirstViewController : UIViewController
/* Hold the boolean value (or whatever value should be
set by the second view controller) in a publicly
visible property */
@property (nonatomic, assign) BOOL someBooleanValue;
/* Provide a method for the second view controller to
request the first view controller to dismiss it */
- (void)dismissSecondViewController;
@end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
@implementation FirstViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/* Get the reference to the second view controller and set
the appropriate property so that the secondViewController
now has a way of talking to the firstViewController */
SecondViewController *vc = [segue destinationViewController];
vc.firstViewController = self;
}
- (void)dismissSecondViewController
{
// Hide the secondViewController and print out the boolean value
[self.navigationController popViewControllerAnimated:YES];
NSLog(@"The value of self.someBooleanValue is %s", self.someBooleanValue ? "YES" : "NO");
}
@end
SecondViewController.h
#import "FirstViewController.h"
@interface SecondViewController : UIViewController
// Create a 'weak' property to hold a reference to the firstViewController
@property (nonatomic, weak) FirstViewController *firstViewController;
@end
SecondViewController.m
@implementation SecondViewController
/* When required (in this case, when a button is pressed),
set the property in the first view controller and ask the
firstViewController to dismiss the secondViewController */
- (IBAction)buttonPressed:(id)sender {
self.firstViewController.someBooleanValue = YES;
[self.firstViewController dismissSecondViewController];
}
@end
Of course, the most correct way to handle this sort of inter-viewController communication is to use protocols/delegates/data sources so that the SecondViewController doesn't need to know the specifics of its parent/owner object. However, sometimes it is quicker/simpler to build a solution like this just to prove the concept. Then if all is well and the code is worth keeping, refactor to use protocol(s).
In the case where view controllers don't - and shouldn't - know about each other, it may be necessary to use NSNotificationCenter. Don't use global variables or NSUserDefaults for communication between view controllers.
Upvotes: 1
Reputation: 2783
There is View-independent value keeping tool. You can use:
[[NSUserDefaults standardUserDefaults]setObject:<#(id)#> forKey:<#(NSString *)#>]
For example, you inputs strings or datas in A view, you can store them in above variables. And then, in B view, you can use them by below code:
[[NSUserDefaults standardUserDefaults]objectOrKey:<#(NSString *)#>]
These are a example of NSUserDefaults
data using:
View A:
- (void)textFieldDidEndEditing:(UITextField *)sender
{
if (sender == homepage) {
[[NSUserDefaults standardUserDefaults]
setURL:[NSURL URLWithString:homepage.text] forKey:Ever5secHomepagePrefKey];
if( [homepage canResignFirstResponder] ) {
[homepage resignFirstResponder];
}
} else if (sender == userId) {
[[NSUserDefaults standardUserDefaults]
setObject:userId.text forKey:Ever5secUserIdPrefKey];
objectForKey:Ever5secUserIdPrefKey]);
if( [userId canResignFirstResponder] ) {
[userId resignFirstResponder];
}
} else if (sender == password) {
[[NSUserDefaults standardUserDefaults]
setObject:password.text forKey:Ever5secPasswordPrefKey];
if( [password canResignFirstResponder] ) {
[password resignFirstResponder];
}
}
}
View B:
userId.text = [[NSUserDefaults standardUserDefaults]
objectForKey:Ever5secUserIdPrefKey];
password.text = [[NSUserDefaults standardUserDefaults]
objectForKey:Ever5secPasswordPrefKey];
homepage.text = [[[NSUserDefaults standardUserDefaults]
URLForKey:Ever5secHomepagePrefKey]
description];
Upvotes: 2
Reputation: 12093
This is not a good encapsulation answer but without being able to use protocols or delegates I don't believe it will have good encapsulation.
You can also create a global variable that you can set in one view controller and access in another.
ViewControllerOne.h
extern NSString *globalVariable;
@interface ViewControllerOne
@end
ViewControllerOne.m
#import "ViewControllerOne.h"
@implementation ViewControllerOne
NSString *globalVariables = @"Some String in the variable to access in second controller";
@end
ViewControllerTwo.m
#import "ViewControllerTwo.h"
#import "ViewControllerOne.h"
@implemetation ViewControllerTwo
- (void)viewDidLoad
{
NSLog("%@", globalVariables);
}
@end
This will print out into the console
****CONSOLE****
Some String in the variable to access in second controller
Upvotes: 3
Reputation: 22559
A question on this topic should really be focused more on NSNotificationCenter
rather than NSUserDefaults
, taking note that both are singletons.
NSUserDefaults
:
The purpose of this class is NOT to pass variables between classes. It's purpose is, well, to store user's defaults. (ie preferences, settings, ... etc).
NSNotificationCenter
:
This class is very handy, and has many different uses, one of which is to broadcast a variable for any class to receive. The receiving class is called the observer. This pattern is known as the Observer Pattern.
NOTE: The NSUserDefaults
approach has the advantage of allowing you to set the variable before the other class is initialized, and can be retrieved at anytime. However, that's really sloppy (IMHO) and considered bad practice.
Quick and Dirty code sample on NSNotificationCenter
:
// upon initializing the class that wants to observe the changes, we add it as an observer.
// So, somewhere in the A.m, upon being initialized (init, maybe?).
- (id)init {
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(calledUponNotif:)
name:@"MyObserveKey"
object:nil];
}
return self;
}
// the selector should look something like this:
- (void)calledUponNotif:(NSNotification *)notif {
id sentVar = [notif object];
}
// Somewhere in the B.m
[[NSNotificationCenter defaultCenter] postNotificationName:@"MyObserveKey"
object:varToSend];
Another note: After calling the postNotification method, the registered selector in the other class will be called synchronously, so you don't have to worry about that.
Upvotes: 7