I'm working on my app but i need some help.
I need a 'php-like session' in Objective C (without using connection to the internet)
I've thought about global vars, but my app seems to reset them when reloading the view.
This is my current code
SecondViewController.h
#interface SecondViewController : UIViewController
{
NSString * string;
}
SecondViewController.m
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (! [string isEqualToString:#"Hello"])
{
NSLog(#"Hello");
string = #"Hello";
}
else
{
NSLog(#"Bye");
}
}
#end
But everytime I reload SecondViewController the 'string' is reseted to its default value.
I'm looking for something that we use in php (a.e. $_SESSION['string'] = 'hello')
It could be helpful to you . It stores the values until unless delete the app from your device .
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:#"TextToSave" forKey:#"keyToLookupString"];
// saving an NSInteger
[prefs setInteger:42 forKey:#"integerKey"];
// saving a Double
[prefs setDouble:3.1415 forKey:#"doubleKey"];
// saving a Float
[prefs setFloat:1.2345678 forKey:#"floatKey"];
// This is suggested to synch prefs, but is not needed (I didn't put it in my tut)
[prefs synchronize];
**Retrieving**
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myString = [prefs stringForKey:#"keyToLookupString"];
// getting an NSInteger
NSInteger myInt = [prefs integerForKey:#"integerKey"];
// getting an Float
float myFloat = [prefs floatForKey:#"floatKey"];
Related
1.Whatever I do the saveButton method won't save and it still returns 0 for REJECTIONS
2.Please help me fix my saveButton to userdefaults method
3.I've tried multiple things and the values still won't change
#import "CCViewController.h"
#interface CCViewController ()
#end
#implementation CCViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// [NSUserDefaults integerForKey:#"REJECTIONS"];
self.rejectLabel.text=REJECTIONS;
self.acceptedLabel.text=ACCEPTED;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.customInputTextField resignFirstResponder];
}
- (IBAction)resetButton:(UIButton *)sender {
self.rejectLabel.text=#"0";
self.acceptedLabel.text=#"0";
}
- (IBAction)rejectButton:(UIButton *)sender {
int current=stringToInt(self.rejectLabel.text);
int test=stringToInt(self.customInputTextField.text);
if (test>0) {
self.rejectLabel.text=self.customInputTextField.text;
self.customInputTextField.text=nil;
} else {
current++;
self.rejectLabel.text=intToString(current);
}
if (stringToInt(self.rejectLabel.text)==3000) {
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Achievement Message" message:#"You have reached 3000 rejections!" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles: nil];
[alertView show];
}
}
NSInteger stringToInt(NSString *string) {
return [string integerValue];
}
NSString* intToString(NSInteger integer) {
return [NSString stringWithFormat:#"%d", integer];
}
- (IBAction)acceptedButton:(UIButton *)sender {
int current=stringToInt(self.acceptedLabel.text);
int test=stringToInt(self.customInputTextField.text);
if (test>0) {
self.acceptedLabel.text=self.customInputTextField.text;
self.customInputTextField.text=nil;
} else {
current++;
self.acceptedLabel.text=intToString(current);
}
NSLog(#"after is: %i", current);
}
- (IBAction)unrejectButton:(UIButton *)sender {
int current=stringToInt(self.rejectLabel.text);
current--;
if (current>=0) {
self.rejectLabel.text=intToString(current);
} else {UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Error Message" message:#"You can not have negative rejections!" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];}
NSLog(#"after is: %i", current);
}
- (IBAction)saveButton:(UIButton *)sender {
NSString *rejected=self.rejectLabel.text;
int reject=intToString(self.rejectLabel.text);
NSString *accepted=self.acceptedLabel.text;
NSUserDefaults *rejectTry=[NSUserDefaults standardUserDefaults];
[rejectTry setObject:self.rejectLabel.text forKey:REJECTIONS];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setValue:#"reject" forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setValue:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setObject:#"accepted" forKey:ACCEPTED];
}
NSLog(#"test save %# & %# & %# & %#", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text);
[rejectTry synchronize];
NSLog(#"test save %# & %# & %# & %#, &a %i", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text, picker_value);
}
- (IBAction)loadButton:(id)sender {
self.rejectLabel.text=REJECTIONS;
self.acceptedLabel.text=ACCEPTED;
}
#end
Still not saving to the keys rejections and accepted
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.acceptedLabel.text forKey:ACCEPTED];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"test save %# & %# & %# & %# pointers %# %#", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text, defaults, prefs);
It looks like you have muddled up your pointers. You have two references to the same instance of userDefaults yet you expect different results when writing to each one. Here, lets walk through your code
NSString *rejected=self.rejectLabel.text;
int reject=intToString(self.rejectLabel.text);
NSString *accepted=self.acceptedLabel.text;
NSUserDefaults *rejectTry=[NSUserDefaults standardUserDefaults];
Lets stop here. standardUserDefaults is a singleton object. You are not creating a user defaults object when you call this method. You then go on to set a value
[rejectTry setObject:self.rejectLabel.text forKey:REJECTIONS];
This works fine.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
Now you have written over your previous value!
[[NSUserDefaults standardUserDefaults] setValue:#"reject" forKey:REJECTIONS];
And you do it again!
[[NSUserDefaults standardUserDefaults] setValue:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setObject:#"accepted" forKey:ACCEPTED];
Conclusion
What you should be doing is creating a local variable like this NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; Then use this for all your writes. Then you will see how you are overwriting the value with key REJECTIONS multiple times
I have some problems on save the position of switch,any help?
- (IBAction)SWitchActionAño:(id)sender {
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
if (switchAño.on) {
[standardDefaults setBool:YES forKey:#"SwitchState"];
NSDateFormatter *formatter=[[NSDateFormatter alloc]init];
[formatter setDateFormat:#"MMM dd,yyyy HH:mm"];
diadelasemanalabel.text=[formatter stringFromDate:[NSDate date]];
} else {
[standardDefaults setBool:NO forKey:#"SwitchState"];
Año.text=#"";
}
}
but i have the problem here! I dont know what is the property!
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
//the error here:property switchAño not found on object....
if ([standardDefaults objectForKey:#"SwitchState"])
self.switchAño.on =[standardDefaults boolForKey:#"SwitchState"];
Try this in viewDidLoad
-(void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *standardDefaults = [[NSUserDefaults standardUserDefaults];
if ([standardDefaults boolForKey:#"SwitchState"] == YES) {
self.switchAño.on = YES;
}
else {
self.switchAño.on = NO
}
In my OS X app, I'm trying to save and retrieve the tag of a radio button. The error occurs on the line marked "<-HERE" in setPreferenceRotor. There is a valid tag coming in.
// PreferenceController.h
extern NSString * const myCellKey;
extern NSString * const myMatrixChangedNotification;
#interface PreferenceController:NSWindowController
{
IBOutlet NSMatrix *matrixRotor;
}
- (IBAction)setRotorTag:(id)sender;
+ (NSInteger)preferenceRotorTag;
+ (void)setPreferenceRotor:(NSInteger)matrixTag;
#end
// PreferenceController.m
NSString * const myMatrixChangedNotification = #"myRotorChanged";
#implementation PreferenceController
- (void)windowDidLoad
{
[super windowDidLoad];
[matrixRotor selectCellWithTag:[PreferenceController preferenceRotorTag]];
}
+ (NSInteger)preferenceRotorTag
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *tagAsData = [defaults objectForKey:myCellKey];
return [NSKeyedUnarchiver unarchiveObjectWithData:tagAsData];
}
+ (void)setPreferenceRotor:(NSInteger)matrixTag
{
//NSInteger mt = matrixTag;
NSData *tagAsData = [NSKeyedArchiver archivedDataWithRootObject:matrixTag]; **//<-HERE**
[[NSUserDefaults standardUserDefaults]setObject:tagAsData forKey:myCellKey];
}
You are passing a primitive (non-object) value, of type NSInteger from variable matrixTag, to a method, archivedDataWithRootObject:, which expects an object reference value. That method happily tries to use the value (which is probably the integer 16, 0x10) as an object reference, and kaboom...
Your thinking looks correct, you know you cannot store non-object values in user defaults, and so you must wrap them as objects first. It is just your way of doing so that is wrong. What you need here is to create an instance of NSNumber from your integer. You could write:
NSNumber *tagAsNumber = [NSNumber numberWithInteger:matrixTag];
[[NSUserDefaults standardUserDefaults] setObject:tagAsNumber forKey:myCellKey];
However this pattern is common enough that a shortcut is provided:
[[NSUserDefaults standardUserDefaults] setInteger:matrixTag forKey:myCellKey];
and this will create the NSNumber object for you. There is also a corresponding integerForKey: method which will unwrap the integer for you when reading.
I am moving images around in my app which is working fine. The problem is that I'd like to keep the images in place when the user comes back to that view. At present, I am using a string to hold the image centre:
NSString *centre = NSStringFromCGPoint(image.center);
I have an NSUserDefault variable called theCentre:
theCentre = [NSUserDefaults standardUserDefaults];
which I try to save using:
[theCentre setObject:centre forKey:#"centre"];
When I output the log, I get the following:
{280, 320}
which is great.
In the viewDidLoad, I have tried the exact same log and it is returning (null). I take it that this means it isn't saving theCentre properly. Am I missing something fundamental here because I have used NSUserDefaults elsewhere in my app and it has been working ok. Many thanks in advance.
Edit: this is the whole code to try and aid debugging :)
-(void)getBounds
{
lowerBoundX = 250;
upperBoundX = 310;
lowerBoundY = 290;
upperBoundY = 350;
}
#pragma mark -
#pragma mark UIPanGestureRecognizer selector
- (void) dragGesture:(UIPanGestureRecognizer *) panGesture
{
[self getBounds];
CGPoint translation = [panGesture translationInView:self.view];
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:{
originalCentre = dragImage.center;
}
break;
case UIGestureRecognizerStateChanged:{
dragImage.center = CGPointMake(dragImage.center.x + translation.x,
dragImage.center.y + translation.y);
}
break;
case UIGestureRecognizerStateEnded:{
if (((dragImage.center.x >= lowerBoundX) && (dragImage.center.y >= lowerBoundY) &&
(dragImage.center.x <= upperBoundX) && (dragImage.center.y <= upperBoundY))) {
dragImage.center = CGPointMake(280, 320);
[dragImage setUserInteractionEnabled:NO];
theCentre = [NSUserDefaults standardUserDefaults];
NSString *centre = NSStringFromCGPoint(dragImage.center);
[theCentre setObject:centre forKey:#"centre"];
NSLog(#"%#", [theCentre objectForKey:#"centre"]);
[theCentre synchronize];
break;
}
[UIView animateWithDuration:0.5
animations:^{
dragImage.center = originalCentre;
}
completion:^(BOOL finished){
}];
}
break;
default:
break;
}
[panGesture setTranslation:CGPointZero inView:self.view];
}
-(IBAction)clear{
[UIImageView animateWithDuration:0.5 animations:^{
dragImage.center = CGPointMake(100, 200);
}];
[dragImage setUserInteractionEnabled:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#", [theCentre objectForKey:#"centre"]);
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragGesture:)];
[dragImage addGestureRecognizer:panGesture];
[dragImage setUserInteractionEnabled:YES];
}
Data saved in NSUserDefaults is first cached and thus it is not available instantly from other instances of the NSUserDefaults. The data is saved periodically on some predefined events/time intervals. However you can force a data synchronization by calling synchronize like this:
NSString *theCenter = NSStringFromCGPoint(image.center);
theCenter = [NSUserDefaults standardUserDefaults];
[theCenter setObject:centre forKey:#"center"];
[theCenter synchronize];
I'm having trouble setting up a model object to save the visual state of user generated CALayers in a simple graphics application for the iphone.
I'm attempting to save the background color and frame of all the current layers on screen by passing those properties to model objects which implement the NSCoding protocol and then into an NSMutableArray which the app delegate owns. Then I archive the array with NSKeyedArchiver and store it in the NSUserDefaults.
Each CALayer's backgroundColor property is converted to a UIColor to be encoded by the model object for storage. I think that I'm unarchiving the array incorrectly or not restoring state from the unarchived array correctly. When I attempt to access the UIColor object that was store in the model object, I get an EXC_BAD_ACCESS.
I thought it was possibly a bug with encoding UIColor objects so tried pulling the values out of the CGColorRef with the CGColorGetComponents function and storing them in an array to encode and archive, but I had the same result of bad access after unarchiving, so I think I'm just doing it wrong.
This is my model object:
#interface AILayerData : NSObject <NSCoding> {
UIColor* color;
CGRect frame;
}
#property (retain) UIColor* color;
#property (assign) CGRect frame;
#end
#implementation AILayerData
#synthesize color;
#synthesize frame;
- (void)encodeWithCoder:(NSCoder *)coder;
{
[coder encodeObject:color forKey:#"color"];
[coder encodeCGRect:frame forKey:#"frame"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
self = [[AILayerData alloc] init];
if (self != nil)
{
color = [coder decodeObjectForKey:#"color"];
frame = [coder decodeCGRectForKey:#"frame"];
}
return self;
}
#end
And this is my archiving implementation:
#implementation AppDelegate
- (void)applicationWillTerminate:(UIApplication *)application {
NSArray *layersArray = viewController.view.layer.sublayers;
dataArray = [NSMutableArray array];
for(AILayer *layer in layersArray)
{
AILayerData *layerData = [[AILayerData alloc] init];
layerData.frame = layer.frame;
UIColor *layerColor = [UIColor colorWithCGColor:layer.backgroundColor];
layerData.color = layerColor;
[dataArray addObject:layerData];
[layerData release];
}
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:layerDataArray] forKey:#"savedArray"];
}
#end
And here is where I restore state:
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
spaceView = [[AISpaceView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view = spaceView;
[spaceView release];
spaceView.delegate = self;
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"savedArray"];
if (dataRepresentingSavedArray != nil) {
[self restoreStateWithData:dataRepresentingSavedArray];
}
}
- (void)restoreStateWithData:(NSData *)data
{
NSArray *savedLayers = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if (savedLayers != nil) {
NSArray *restoredLayers = [[NSArray alloc] initWithArray:savedLayers];
for(AILayerData *layerDataObject in restoredLayers) {
UIColor *layerColor = layerDataObject.color;
AILayer *newLayer = [[AILayer alloc] init];
newLayer.backgroundColor = layerColor.CGColor;
newLayer.frame = layerDataObject.frame;
newLayer.isSelected = NO;
[self.view.layer addSublayer:newLayer];
[newLayer release];
}
[restoredLayers release];
[spaceView.layer layoutSublayers];
}
}
#end
Any help with this is greatly appreciated. I'm pretty much a noob. I was encoding, archiving and unarching an NSArray of NSNumbers converted from the color's floats in pretty much the same way and getting bad access.
You certainly want to retain the color in initWithCoder:
color = [[coder decodeObjectForKey:#"color"] retain];
or, with the dot syntax as color was declared as a retain property:
self.color = [coder decodeObjectForKey:#"color"];
You are over-releasing layerColor: You don't own it (layerDataObject does), but you are releasing it.
It looks like NSCoder for iPhone doesn't respond to -encodeWithCGRect:
Source: http://17.254.2.129/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSCoder_Class/Reference/NSCoder.html