Storing results after screen is disappear - iphone

I am developing a game,in that i want to add the points continuously,for this i used plist but whenever the screen is disappear and starts then plist starts again.what to do?
Thanks in Advance.

To add more info to Ahmed's answer you should implement in your AppDelegate.m three methods like this:
AppDelegate.h
NSNumber *gamescore;
#property(nonatomic, strong) NSNumber *gamescore;
#define UIAppDelegate \
((AppDelegate *)[UIApplication sharedApplication].delegate)
AppDelegate.m
#synthesize gamescore;
- (BOOL) checkFirstRun {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSNumber *defaultcheck;
defaultcheck = [defaults objectForKey:#"GameScore"];
if (defaultcheck==nil) {
return TRUE;
} else {
return FALSE;
}
}
- (void) storeGlobalVars {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:gamescore forKey:#"GameScore"];
[defaults synchronize];
}
- (void) readGlobalVars {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
gamescore = [defaults objectForKey:#"GameScore"];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
// ...
if ([self checkFirstRun]) {
// first run, lets create basic default values
gamescore = [NSNumber numberWithInt:0];
[self storeGlobalVars];
} else {
[self readGlobalVars];
}
// ...
Later in your application, after importing AppDelegate.h you can use the UIAppDelegate.gamescore to access the AppDelegate's property.
And you have to remember that gamescore is an NSNumber object, you have to manipulate it using NSNumber's numberWithInt and/or intValue.
The CheckFirstRun is needed because your user's device at application first run doesn't contain the default plist and the initial values, you have to create an initial set.

You can make AppDelegate variables and store it in them. There scope remains in the complete application until the application closes.
In AppDelegate.h
for example
NSString *string;
#property(nonatomic, strong) NSString *string;
In AppDelegate.m
#synthesize string;
in applicationDidFinishLaunchingWithOptions
string = #"";
And then is your classes
add #import "AppDelegate.h"
then in your code
((AppDelegate *)[UIApplication SharedApplication].Delegate).string = #"1";

Related

Overwrite a value saved in NSUserDefaults

I have this method to save a mutable array named myWallet that contains instances of the Class Card.
- (void)saveMyWallet
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:self.myWallet] forKey:#"myWalletArray"];
[defaults synchronize];
}
The Card Class that I have has three instance variables: name, pin, and points. So far, saving new instances of the Card in UserDefaults is ok. I would just like to know some suggestions on how can I overwrite the value of points because as I proceed in the computation of points, I want to update it.
Here is my Card Class
Card.h
#import <Foundation/Foundation.h>
#interface Card : NSObject <NSCoding>
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *pin;
#property (nonatomic, strong) NSNumber *points;
#property (nonatomic, strong) NSMutableArray *pointsToDeduct;
- (double) subtractPoints: (double) requiredPoints;
- (void) encodeWithCoder:(NSCoder *)coder;
- (id) initWithCoder: (NSCoder *)coder;
#end
Card.m
#import "Card.h"
#implementation Card
#synthesize name = _name;
#synthesize pin = _pin;
#synthesize points = _points;
#synthesize pointsToDeduct = _pointsToDeduct;
- (id)initWithCoder:(NSCoder *)coder
{
self = [[Card alloc] init];
if(self != nil) {
self.name = [coder decodeObjectForKey:#"name"];
self.pin = [coder decodeObjectForKey:#"pin"];
self.points = [coder decodeObjectForKey:#"points"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.name forKey:#"name"];
[coder encodeObject:self.pin forKey:#"pin"];
[coder encodeObject:self.points forKey:#"points"];
}
- (double) subtractPoints:(double) requiredPoints
{
double latestPoints;
latestPoints = ([self.points doubleValue] - requiredPoints);
return latestPoints;
}
#end
And lastly, here is the delegate method by which the new value of the points (named resultingPoints) should come from.
- (void)perksDetailsViewController:(PerksDetailsViewController *)sender didPassRequiredPoints:(NSNumber *)requiredPoints withCard:(Card *)selectedCard
{
double perksPoints = [requiredPoints doubleValue];
self.resultingPoints = [NSNumber numberWithDouble:[selectedCard subtractPoints:perksPoints] ];
NSLog(#"points remaining %#", self.resultingPoints);
}
Bombard me with suggestions :) Thanks in advance!
From what I see, you actually save your object as NSData, so the logical approach is to get it back from the user defaults, unarchive it, update the properties, archive it and save it back to the user defaults.
Retrive the data from NSUserDefaults into runtime,Delete previous object for key and write back updated value.

NSUserDefaults: returning integer, not returning NSArray

I'm trying to store both an integer and NSArray with the NSUserDefaults, but I only can correctly retrieve the integer. When I try to recover the NSArray, it returns an empty array.
I start with a custom class XMLParser.m.
//XMLParser.m
//NSArray 'stored' correctly contains 10 data objects. 'stored' is an NSArray property of the XMLParser class
numberOfEvents = [stored count];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:stored forKey:#"eventsList"];
[defaults setInteger:numberOfEvents forKey:#"numberOfEvents"];
[defaults synchronize];
But when I try to access the data in another class, ie. my AppDelegate, I get an empty NSArray
//myApplicationAppDelegate.m
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int value = [defaults integerForKey:#"numberOfEvents"]; //returns 10
parsedEventsList = [defaults arrayForKey:#"eventsList"]; //parsedEventsList is an NSArray property of myApplicationAppDelegate class
int value2 = [parsedEventsList count]; //***returns 0***
I've even tried using
[defaults objectForKey:#"eventsList"]
and it's still returning nothing.
Thoughts? Thanks!
All of your objects in the stored array must be property list objects (i.e. instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary).
Your problem appears to be that your objects are all custom.
I think you may have forgotten to make them serializable if you add code similar to this (for each of your objects) then it should work
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.obj1 forKey:#"obj1"];
[encoder encodeObject:self.obj2 forKey:#"obj2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.obj1 = [decoder decodeObjectForKey:#"obj1"];
self.obj2 = [decoder decodeObjectForKey:#"obj2"];
}
return self;
}

NSString variable available throughout program

I have this line of code:
NSString *dateString = [self.dates objectAtIndex:row];
that gets set when a user selects a row in a picker. I'd like to have this code available everywhere and not just in the picker select area. Other wise I get a "dateString" is undeclared error message of course.
how would i go about doing this?
thanks for any help.
Why don't you use the singleton design pattern ? To me, it seems to be a cleaner solution that solutions posted above.
VariableStore.m
#import "VariableStore.h"
#implementation VariableStore
#synthesize dateString;
+ (VariableStore *)sharedInstance
{
static VariableStore *myInstance = nil;
if (nil == myInstance)
myInstance = [[[self class] alloc] init];
return myInstance;
}
#end
VariableStore.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface VariableStore : NSObject
{
NSString *dateString;
}
+ (VariableStore *)sharedInstance;
#property (nonatomic, retain) NSString *dateString;
#end
AnyClassWhereYouWantToUseYourVariable.h
#import "VariableStore.h"
AnyClassWhereYouWantToUseYourVariable.m
NSLog("dateString = %#", [VariableStore sharedInstance].dateString);
A simple, but not very elegant solution is to use NSUserDefaults.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:#"TextToSave" forKey:#"keyToLookupString"];
[prefs synchronize];
// getting an NSString
NSString *myString = [prefs stringForKey:#"keyToLookupString"];
Define as a global variable in your interface file(.h) file. If you want to use in other class as well make the property and synthesize it.
Use this code. You can save the entire string.
Just create NSString object of
in (YourDelegare.h) file
NSString * dateString;
in (YourDelegare.m) file
-(void) saveMyState
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:dateString forKey:#"dateString"];
[prefs synchronize];
}
- (void) retrieveMyState
{
//Retrieving
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
dateString = [prefs stringForKey:#"dateString"];
}
just call these methods wherever required.
Or you can declare that variable in your delegate file.
In yourdelegate.h:
NSString *yourString;
#property (nonatomic, retain) NSString *yourString;
In yourdelegate.m:
#synthesize yourString;
In viewcontrolller.h:
yourdelegate *appDelegate;
In viewcontrolller.m:
appDelegate = [[UIApplication sharedApplication] delegate]; // in viewDidLoad
appDelegate.yourString = [self.dates objectAtIndex:row]; // where ever you need
And, like magic, it's a global variable now.

Can't read NSUserDefaults data between views

Disclaimer: major noob
I'm writing an arithmetic flash card app as a learning project. I have a UITabViewController with the bottom tab bar that toggles between a few different views. Everything works okay until I try to set NSUserDefault boolean values in the Settings view controller and try to read those values in the Flashcards view controller.
The settings view has a switch to enable/disable each operator (addition, subtraction, etc) and the flashcard view should randomly present a flash card if that type of operation was enabled.
I believe that my mistake is that I don't understand the key concept of data encapsulation, objects, etc. I'd appreciate any help.
Here is the Settings view controller. I'm not even sure how to put the code into this forum so this might be a laughable moment... here goes:
// settings_flashcards.h
#import <UIKit/UIKit.h>
#interface settings_flashcards : UIViewController {
UISwitch *additionSwitch;
UISwitch *subtractionSwitch;
UISwitch *multiplicationSwitch;
UISwitch *divisionSwitch;
}
#property (nonatomic,retain) IBOutlet UISwitch *additionSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *subtractionSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *multiplicationSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *divisionSwitch;
#end
and...
/ settings_flashcards.m
#import "settings_flashcards.h"
#implementation settings_flashcards
#synthesize additionSwitch;
#synthesize subtractionSwitch;
#synthesize multiplicationSwitch;
#synthesize divisionSwitch;
- (void)viewDidLoad {
[additionSwitch addTarget:self action:#selector(additionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[subtractionSwitch addTarget:self action:#selector(subtractionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[multiplicationSwitch addTarget:self action:#selector(multiplicationSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[divisionSwitch addTarget:self action:#selector(divisionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
}
-(void) additionSwitchFlipped {
if (additionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"additionKey"];
}
}
-(void) subtractionSwitchFlipped {
if (subtractionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"subtractionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"subtractionKey"];
}
}
-(void) multiplicationSwitchFlipped {
if (multiplicationSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"multiplicationKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"multiplicationKey"];
}
}
-(void) divisionSwitchFlipped {
if (divisionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"divisionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"divisionKey"];
}
}
Here is the Flashcards view...
// flashcardsViewController.h
#import <UIKit/UIKit.h>
#interface flashcardsViewController : UIViewController <UIActionSheetDelegate>{
UILabel *firstNumberLabel;
UILabel *secondNumberLabel;
UILabel *answerNumberLabel;
UILabel *operatorLabel;
BOOL additionIsEnabled;
BOOL subtractionIsEnabled;
BOOL multiplicationIsEnabled;
BOOL divisionIsEnabled;
}
#property (nonatomic,retain) IBOutlet UILabel *firstNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *secondNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *answerNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *operatorLabel;
-(void) buttonClicked:(id)sender;
#end
and...
// flashcardsViewController.m
#import "flashcardsViewController.h"
#implementation flashcardsViewController
#synthesize firstNumberLabel;
#synthesize secondNumberLabel;
#synthesize answerNumberLabel;
#synthesize operatorLabel;
- (void)viewDidLoad {
srand(time(0)); //seed random
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"subtractionKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"subtractionKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"multiplicationKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"multiplicationKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"divisionKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"divisionKey"];
}
//the following should assign each BOOL variable based on the key
additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"];
subtractionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"subtractionKey"];
multiplicationIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"multiplicationKey"];
divisionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"divisionKey"];
[super viewDidLoad];
}
-(void) buttonClicked:(id)sender{
int a = rand() % 4;// random number generator (number to enter loop)
if ( additionIsEnabled || subtractionIsEnabled || multiplicationIsEnabled || divisionIsEnabled) {
while (a < 5) {
switch (a) {
case 0:
if (additionIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x+y)];
operatorLabel.text = [[NSString alloc]initWithFormat: #"+"];
a = 5;
}
else a++;
break;
case 1:
if (subtractionIsEnabled == TRUE){
int x = rand() % 19 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x-y) ];
operatorLabel.text = [[NSString alloc]initWithFormat: #"-"];
a = 5;
}
else a++;
break;
case 2:
if (multiplicationIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x*y)];
operatorLabel.text = [[NSString alloc]initWithFormat: #"×"];
a = 5;
}
else a++;
break;
case 3:
if (divisionIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() % 11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x*y)];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
operatorLabel.text = [[NSString alloc]initWithFormat: #"÷"];
a = 5;
}
else a = 0;
break;
default:
break;
}
}
}
else
{
UIAlertView *noOperatorSelectedAlert = [[UIAlertView alloc]initWithTitle:#"You have not set any operations."
message:#"Return to the settings menu and decide which operations you wish to perform. (addition, subtraction, etc.)"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[noOperatorSelectedAlert show];
[noOperatorSelectedAlert release];
}
}
There are a few things to do here. Firstly you want a better way of saying what the default state is before the user has made any explicit decisions. Next you want to know when you should refresh your in-app state from user preferences.
Defaults Initialization
The first item's solution is to put the default values into the registration domain for your user preferences. This is something you'll do during application initialization, rather than having your views individually check preferences and update them at initialization time. The preferences system looks in quite a few places for data, and the first place it looks is in the in-memory-only registration domain. This is where you'll put the default (i.e. no value specified means 'x') values for each of your user preferences.
The API you'll use for this is -[NSUserDefaults registerDefaults:], which takes an NSDictionary of values. To set your default values of YES (in Objective-C the BOOL type uses YES and NO rather than TRUE and FALSE) you'll use something like this, commonly executed in a +initialize method for your application's main class:
+ (void) initialize
{
// in any +initialize, make sure it's being called on your class
// +initialize is different from all other methods in this respect
if ( [self isKindOfClass: [MyApplicationDelegate class]] == NO )
return; // being called on a superclass, don't do my stuff
// set up default values for certain preferences
NSMutableDictionary * defaults = [NSMutableDictionary new];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"additionKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"subtractionKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"multiplicationKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"divisionKey"];
// set this as the registration domain
[[NSUserDefaults standardUserDefaults] registerDefaults: defaults];
[defaults release];
}
Usually you'll put everything into one method like this, so if you have other parts of the application which expect a default non-zero value for any preference, you should add those to this group and place it into your application delegate's +initialize method.
Now, when your other classes use [[NSUserDefault standardUserDefaults] boolForKey: #"additionKey"] and there is nothing saved to the preference files for that key, they will get the value supplied above.
Refreshing Cached Values
So, you have a view where the user is able to change these preferences. Your next job is to make the view above that update its member variables using the new preferences. For this we can use either delegation or notification. In this case, I'll go with notifications for to reasons:
You're using NSUserDefaults, which can theoretically change in many different places. Delegation would only inform you of changes made by one object.
NSUserDefaults already implements a handy notification which you can watch.
So, in your flashcardsViewController you'll have something like these few methods:
- (void) updateFromPreferences
{
// fetch current values from user defaults into your member variables
additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey: #"additionKey"];
// etc...
}
- (void) viewWillLoad
{
// load variables from user defaults
[self updateFromPreferences];
// find out when the preferences have been changed
// this will cause -updateFromPreferences to be called
// whenever something changes preferences, inside the app or outside
[[NSNotificationCenter defaultNotificationCenter] addObserver: self
selector: #selector(updateFromPreferences)
name: NSUserDefaultsDidChangeNotification
object: nil];
}
- (void) viewDidUnload
{
// always remove notification observers.
[[NSNotificationCenter defaultNotificationCenter] removeObserver: self
name: NSUserDefaultsDidChangeNotification
object: nil];
}
- (void) dealloc
{
// add this to your existing dealloc routine
[[NSNotificationCenter defaultNotificationCenter] removeObserver: self
name: NSUserDefaultsDidChangeNotification
object: nil];
}
Summary
Taken together, these two should give you everything you need to make this work.
In addition to the "always YES" problem pointed out by Chiefly Izzy, your -buttonClicked: method does not read new values from NSUserDefaults. These values are read (once) in [flashcardsViewController viewDidLoad]. If they are changed in settings, the change will not be detected in flashCardsViewController until the next time it is loaded (probably the next time the application is launched).
The simplest approach would be to move your code for reading the IsEnabled BOOL values into the -buttonClicked method, like so:
-(void) buttonClicked:(id)sender {
// the following should assign each BOOL variable based on the key
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
additionIsEnabled = [defaults boolForKey:#"additionKey"];
subtractionIsEnabled = [defaults boolForKey:#"subtractionKey"];
multiplicationIsEnabled = [defaults boolForKey:#"multiplicationKey"];
divisionIsEnabled = [defaults boolForKey:#"divisionKey"];
int a = rand() % 4;
if ( additionIsEnabled || subtractionIsEnabled ...
This code ...
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
... simply always set's additionKey to TRUE. If you would like to check if additionKey is set, do this ...
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
... boolForKey: documentation: If a boolean value is associated with defaultName in the user defaults, that value is returned. Otherwise, NO is returned.
Translated to human language - if there's an value associated with additionKey, this value is returned. If there's no associated value, NO/FALSE is returned.
So, your code does this - if value is not associated with additionKey or if it is set to NO, set it to YES. This leads to this - additionKey is always set to YES/TRUE.

How to define a global variable of type NSUserDefaults and initialize a value?

which is the cleanest way to use something like a global variable? Normally, using a global variable is forbidden, but I don't know a better solution for accessing NSUserDefaults from different classes.
I read a bit and come up with this. I define a Contants.h and a Constants.m file and include them everywhere I need to.
//Constants.h
#import <Foundation/Foundation.h>
#interface Constants : NSObject {
extern NSUserDefaults *settings;
}
#end
.
//Constants.m
#implementation Constants
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"];
NSDictionary *settingsDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
[[NSUserDefaults standardUserDefaults] registerDefaults:settingsDict];
NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
#end
The problem here is that I want to initialize a value to my constant. I have no method in Constants.m. So my helper variables would also be globals?
One thing to mention: I think the global variable also has to be released?
Thanks for your help!
Edit:
#hotpaw2:
AppBundleSingleton.h:
#import <Foundation/Foundation.h>
#interface AppBundleSingleton : NSObject {
}
+ (AppBundleSingleton *)sharedAppBundleSingleton;
#end
AppBundleSingleton.m:
#import "AppBundleSingleton.h"
static AppBundleSingleton *sharedAppBundleSingleton = nil;
#implementation AppBundleSingleton
#pragma mark -
#pragma mark Singleton methods
+ (AppBundleSingleton *)sharedAppBundleSingleton {
#synchronized(self) {
if (sharedAppBundleSingleton == nil) {
sharedAppBundleSingleton = [[self alloc] init];
}
}
return sharedAppBundleSingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedAppBundleSingleton == nil) {
sharedAppBundleSingleton = [super allocWithZone:zone];
return sharedAppBundleSingleton; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
-(id)init {
self = [super init];
sharedAppBundleSingleton = self;
// Initialization code here
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Settings" ofType:#"plist"];
NSDictionary *settingsDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
[[NSUserDefaults standardUserDefaults] registerDefaults:settingsDict];
return self;
}
#end
In my AppDelegate.m I have the following:
// ...
#include "AppBundleSingleton.h"
#implementation MyAppDelegate
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
[AppBundleSingleton sharedAppBundleSingleton];
return YES;
}
// ...
#end
In my ViewController I query the values:
NSString *myString = [[NSUserDefaults standardUserDefaults] stringForKey:#"myKeyforString"];
Would that be a solution?
You don't need to use global variables - you can access the userdefaults from any class or object within your project like this:
BOOL foo = [[NSUserDefaults standardUserDefaults] boolForKey:#"bar"];
As long as you synchronize the userdefaults after every change you make, the data fetched in this way is consistent.
Global variables are not only NOT forbidden, but a required part of the ANSI C specification, which is a subset of Obj C. Both gcc and llvm fully support globals. They are often the smallest and fastest way to pass unprotected values around.
That said, explicit use of global variables are most probably not the solution to your problem. You have a problem quite well suited to the MVC paradigm. Place all your NSDefault code into a singleton model class (an M of the MVC), which can self-initialize on first access (the implementation may use a hidden global), and attach that object to the appDelegate where it can easily be obtained from anywhere. Then encapsulate all you default value read/writes as properties of that object.