Saving NSRect to NSUserDefaults - objective-c

Currently I'm trying to save an NSRect to my user defaults. Right now I'm using a NSValue to wrap it as an object then save it into the user defaults as an object with the following code
[userDefaults setObject:[NSValue valueWithRect:rect forKey:#"Key"]];
However, when I run it, I get an error that says [NSUserDefaults setObject:forKey:]: Attempt to insert non-property value 'NSRect: {{0, 0}, {50, 50}}' of class 'NSConcreteValue'.
Does anyone know how I can fix this? Thanks.

Here is a much simpler solution, using NSString:
// store:
[[NSUserDefaults standardUserDefaults]
setValue:NSStringFromCGRect(frame) forKey:#"frame"];
// retrieve:
CGRect frame = CGRectFromString(
[[NSUserDefaults standardUserDefaults] stringForKey:#"frame"]);
Swift 4
// store
UserDefaults.standard.set(NSStringFromCGRect(rect), forKey: "frame")
// retrieve
if let s = UserDefaults.standard.string(forKey: "frame") {
let frame = CGRectFromString(s)
}

NSValue is not supported by the user defaults.
The value parameter can be only property list objects: NSData,
NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and
NSDictionary objects, their contents must be property list objects.
You need to archive the value into data then unarchive it when you access it.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSRect rect = { 0, 0, 10, 20 };
NSValue *value = [NSValue valueWithRect:rect];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:value];
[userDefaults setObject:data forKey:#"key"];
[userDefaults synchronize];
data = [userDefaults objectForKey:#"key"];
NSValue *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"%#", unarchived);

Related

NSUserDefaults setObject not saving for first time

My application saving NSData (contains bookmarked file reference) list to NSUserDefaults in somewhat following way, at any point of application process:
NSMutableArray *bookmarkedURLs = [[NSMutableArray alloc] init];
[bookmarkedURLs addObject:bookmark]; // 'bookmark' is a NSData object
[[NSUserDefaults standardUserDefaults] setObject:bookmarkedURLs forKey:#"AppBookmarks"];
[[NSUserDefaults standardUserDefaults] synchronize];
When application starts I checked through NSUserDefaults to populate saved NSData list:
bookmarkedURLs = [[[NSUserDefaults standardUserDefaults] objectForKey:#"AppBookmarks"] mutableCopy];
if (bookmarkedURLs.count == 0)
{
bookmarkedURLs = [[NSMutableArray alloc] init];
NSLog(#"INITIALIZED");
}
else
{
NSLog(#"STORES NSDATA LIST");
....
}
The problem I faced I can order in following steps:
There is no saved NSUserDefaults data by 'AppBookmarks' key
Save a NSData to NSUserDefaults by 'AppBookmarks' key
Restarts application
Application tries to populate a NSMutableArray from NSUserDefaults' 'AppBookmarks' key but always found 0 records
I save again a new NSData to 'AppBookmarks' key
Restarts application
Application tries to populate NSMutableArray from 'AppBookmarks' and this time it found saved record(s).
Any restart of application or new NSData addition to 'AppBookmarks' never fails thereafter
So whenever there is no saved data to NSUserDefaults and I saved a value, it's not loading or saving for first time. Any attempt to save and load is working after then.
Try this:
NSMutableArray *bookmarkedURLs = [[NSMutableArray alloc] init];
[bookmarkedURLs addObject:bookmark]; // 'bookmark' is a NSURL object
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:bookmarkedURLs forKey:#"AppBookmarks"];
[defaults synchronize];
I hope this can help you.
You can do something like,
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
// for example
NSURL *url1; // your url1
NSURL *url2; // your url2
//Set data to userdefaults
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:url1,url2, nil]; // Store urls directly in array
NSData *bookMarkdata = [NSKeyedArchiver archivedDataWithRootObject:arr]; // convert whole array in data
[myDefaults setObject:bookMarkdata forKey:#"AppBookmarks"]; // save that data object to userdefaults
[myDefaults synchronize];
//Retreive data from userdefaults
NSData *resultData = [myDefaults objectForKey:#"AppBookmarks"]; //retrieve data from user defaults
NSMutableArray *resultArr = [NSKeyedUnarchiver unarchiveObjectWithData:resultData]; // get result array from data

Saving Custom NSArray Data to iPhone

I have been trying to save locally (through NSUserDefaults) a NSMutableArray of PFGeoPoints that a user creates. After much reading and research, I now know that simply saving an array with custom data is quite frankly impossible. I have tried the following in several different ways:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *testArray = [[NSMutableArray alloc] init];
NSArray *checkArray = [[NSArray alloc] init];
testArray = locationList;
PFGeoPoint *test = [locationList objectAtIndex:0];
NSString *latString = [NSString stringWithFormat:#"%f",test.latitude];
[testArray insertObject:latString atIndex:0];
checkArray = testArray;
[defaults setValue:checkArray forKey:#"Locations"];
[defaults synchronize];
where locationList is a NSMutableArray that has been created and set to PFGeoPoints from Parse.
I had also tried converting the NSMutableArray to NSData via
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
, but this still did not work. Each time I kept receiving the error telling me the following:
Property list invalid for format: 200
(property lists cannot contain objects of type 'CFType')
The NSMutableArray that I am saving is a list that contains multiple PFGeoPoints. All I am trying to do is save this array to the device, so that the user does not have to recreate (render) the entire list each time the user loads the application (I am using cloud data...not trying to spend too much for data).
If someone could help me out with either a suggestion/solution on how to save this data as an array (rather than breaking up each line into integers for lat and long), OR if someone can suggest a helpful alternative to NSUserDefaults (like perhaps Core Data or some other local storage) I would be most appreciative. Thanks
simply you need to implement NSCoding protocol
Write array:
Obj-C
-(void)writeArrayWithCustomObjToUserDefaults:(NSString *)keyName withArray:(NSMutableArray *)myArray {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myArray];
[defaults setObject:data forKey:keyName];
[defaults synchronize];
}
Swift 2.3
func writeArrayWithCustomObjToUserDefaults(keyName: String, withArray myArray: [AnyObject]) {
var defaults = NSUserDefaults.standardUserDefaults()
var data = NSKeyedArchiver.archivedDataWithRootObject(myArray)
defaults.setObject(data, forKey: keyName)
defaults.synchronize()
}
Swift 3.1
func writeArrayWithCustomObj(toUserDefaults keyName: String, withArray myArray: [Any]) {
let defaults = UserDefaults.standard
let data = NSKeyedArchiver.archivedData(withRootObject: myArray)
defaults.set(data, forKey: keyName)
defaults.synchronize()
}
Read Array:
Obj-C
-(NSArray *)readArrayWithCustomObjFromUserDefaults:(NSString*)keyName {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:keyName];
NSArray *myArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[defaults synchronize];
return myArray;
}
Swift 2.3
func readArrayWithCustomObjFromUserDefaults(keyName: String) -> [AnyObject] {
var defaults = NSUserDefaults.standardUserDefaults()
var data = defaults.objectForKey(keyName)!
var myArray = NSKeyedUnarchiver.unarchiveObjectWithData(data)!
defaults.synchronize()
return myArray
}
Swift 3.1
func readArrayWithCustomObj(fromUserDefaults keyName: String) -> [Any] {
let defaults = UserDefaults.standard
let data: Data? = defaults.object(forKey: keyName)
let myArray: [Any]? = NSKeyedUnarchiver.unarchiveObject(with: data!)
defaults.synchronize()
return myArray!
}
To save custom objects into user defaults, it need to conform to NSCoding protocol (objects needs to code/decode).
Your custom Objects need to implement the NSCoding protocol.
Once you followed NSCoding rules; archive & save data like this:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourArray];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"Key"];
Unarchive like this:
NSArray *array= [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"Key"];

NSMutableArray not saved NSUserDefault

I'm trying to save a NSMutableArray with NSUSerDefault and then open the array.
Here some code:
-(IBAction)btnSave{
Class *aClass = [[Class alloc]init];
aClass.idClass=#"aaaxxx";
aClass.nameClass=#"hello";
[myArray addObject:aClass];
NSUserDefaults *arrayDefault=[NSUserDefaults standardUserDefaults];
[arrayDefault setObject:myArray forKey:#"savedArray"];
[arrayDefault synchronize];
}
and
- (void)viewDidLoad
{
[super viewDidLoad];
myArray=[[NSMutableArray alloc]init];
NSMutableArray *savedArray=[[NSUserDefaults standardUserDefaults]objectForKey:#"savedArray"];
if(savedArray!=NULL){
myArray=savedArray;
[tableView reloadData];
}
// Do any additional setup after loading the view from its nib.
}
when I compile and when I push the button, this is what I read on log output:
[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '(
"<Class: 0x8452b40>"
)' of class '__NSArrayM'. Note that dictionaries and arrays in property lists must also contain only property values
and obviously when I reopen the view the array is not loaded.
any help?
NSUserDefaults allows only Premitive DataTypes to be store in it. if you want to store your custom class Object then use following code, for more Detail refer this IOS Documentation
//create an array with your custom class objects
Class *aClass = [[Class alloc]init];
aClass.idClass=#"aaaxxx";
aClass.nameClass=#"hello";
[myArray addObject:aClass];
//convert your array to `NSData` object using `NSKeyedArchiver`
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myArray];
//store it to `NSUserDefaults`
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"myArray"];
[[NSUserDefaults standardUserDefaults] synchronize];
//convert your stored Object back to `NSData` using `NSKeyedUnarchiver`
NSData *storedData = [[NSUserDefaults standardUserDefaults] objectForKey:#"myArray"];
NSArray *storedArr = [NSArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:storedData]];
NSLog(#"%#",storedArr[0]);
First you implement NSCoding in you object class. The in order to save/load the NSMutableArray of those objects you can do:
- (void) loadArray {
//Loading the NSMutableArray
NSData *arrayData = [[NSUserDefaults standardUserDefaults] objectForKey:#"ArrayKey"];
myArray = [NSKeyedUnarchiver arrayData];
}
-(void) saveArray {
//Saving the NSMutableArray
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:myArray];
[[NSUserDefaults standardUserDefaults] setObject:arrayData forKey:#"ArrayKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
For more info I suggest looking at a longer tutorial. For example Ray Wenderlich's How to Save your App Data with NSCoding And NSFileManager is a good one.
You need to implement NSCoding protocol in your model object Class. It is needed to serialize and deserialize non standard data to NSUserDefaults.
Now you can use NSKeyedArchiver to convert the object to data and store in userDefaults. Use NSKeyedUnarchiver to convert the data back to the object from defaults.
//h file
#interface Class : NSObject<NSCoding>
#property (nonatomic, copy) NSString *idClass;
#property (nonatomic, copy) NSString *nameClass;
//m File
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self.idClass forKey:#"IDClass"];
[aCoder encodeObject:self.nameClass forKey:#"NameClass"];
}
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
self.idClass = [aDecoder decodeObjectForKey:#"IDClass"];
self.nameClass = [aDecoder decodeObjectForKey:#"NameClass"];
}
return self;
}
After implementing the NSCoding you can archive them to store as data in userDefaults
//Saving array
Class *aClass = [[Class alloc]init];
aClass.idClass=#"aaaxxx";
aClass.nameClass=#"hello";
[myArray addObject:aClass];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myArray];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:#"savedArray"];
[defaults synchronize];
//Retrieving
NSData *data = [defaults objectForKey:#"savedArray"];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Setting value in nsuserdefaults

I'm new to Objective-C and XCode and I've encountered such a problem.
How do you properly save the value to NSUserDefaults.
I have value in
[_textFields objectAtIndex:2]).text
And trying to do this
[[[NSUserDefaults standardUserDefaults] setValue:((UITextField *)[_textFields objectAtIndex:2]).text)) forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
How do you do it properly?
Use setObject:forKey: instead of setValue:forKey:
[[[NSUserDefaults standardUserDefaults] setObject:((UITextField *)[_textFields objectAtIndex:2]).text)) forKey:#"Phone"];
Update:
You code will work if you really have that text field in the array. Here is the step by step broken down code to make it more clear:
UITextField* textField = [_textFields objectAtIndex:2]; // get your text field
NSString* text = textField.text; // get the actual value we are going to store
[[[NSUserDefaults standardUserDefaults] setObject:text forKey:#"Phone"]; // store it
You are working with strings values. You should use setObjectForKey (save) and objectForKey (read). Here's an example
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *yourText = [[_textFields objectAtIndex:2] text]; // Your text
// Save
[userDefaults setObject:yourText forKey:kKey];
[userDefaults synchronize];
// Read
NSString *result = (NSString *) [userDefaults objectForKey:kKey];
Use method setObject:forKey: instead of setValue:forKey:
In NSUserDefaults class:
[[NSUserDefaults standardUserDefaults] setObject:"Your Object" forKey:#"Phone"];
You need to use the setObject:forKey: if you want to store property list objects (dictionaries, arrays, strings and numbers) in NSUserDefaults. See the docs.

AVAudioPlayer and NSUserDefaults

[PlaySound stop];
[PlaySound prepareToPlay];
[[NSUserDefaults standardUserDefaults] synchronize];
text = [[NSUserDefaults standardUserDefaults] stringForKey:#"defaulttext"];
NSLog(#"%#",text);
BOOL loop = [prefs boolForKey:#"switch"];
NSLog(#" %d",loop);
do {
[PlaySound play];
} while (loop ==YES);
There are two major problems I am facing with this code.
1) This is a function which is called when a button is tapped... I am allocating the audio player in this function. Whenever this function is called I called the stop function on audio player yet it does not stop and two sounds play simultaneously.
2) My defaults are not registering correctly. Both the string and bool are showing nil in console.
I haves added settings bundle in my app.
Edit: Rest of the method
NSUInteger selectedRow= [SoundPicker selectedRowInComponent:0];
NSString *userchoice =[self pickerView:SoundPicker titleForRow:selectedRow forComponent:0];
NSString *soundpath = [[NSBundle mainBundle] pathForResource:userchoice ofType:#"wav"];
NSURL *fileURl = [[NSURL alloc] initFileURLWithPath:soundpath];
NSError **error = nil;
PlayFartSound = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURl error:error];
I have sorted the problem of audio player.
Can anyone please help on NSUserDefaults.
In my settings root plist I have a text field with identifier name name_preference so I put this in code:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
text = [defaults stringForKey:#"name_preference"];
NSLog(#"%# abc",text);
The log is (null) abc ? [I have set the default value to hello in plist]
How are you setting the default values in your NSUserDefaults? You say you've got the defaults in a plist, but when do you load that plist into NSUserDefaults?
To set the default NSUserDefaults values, you need to call this somewhere early in your program, ideally in somewhere like applicationDidFinishLaunching
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
Where 'defaults' is a dictionary of default settings, possibly loaded from a plist.