NSUserDefaults setObject not saving for first time - objective-c

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

Related

App is crashing on NSUserDefaults setObject:forKey:

While setting object to NSUserDefaults my App is crashing Randomly in iOS 12.Below is my code where the crash occurs
shared2 = [[NSUserDefaults alloc]initWithSuiteName:#"group.AppName"];
NSData *datashare = [NSKeyedArchiver archivedDataWithRootObject:_sharedData];
[shared2 setObject:datashare forKey:#"dicForToday"];
Not getting any crash logs as it happens randomly
Frequency of this crash is much more on iOS 12.
Normally you can use this method for save data
Post Method:
[[NSUserDefaults standardUserDefaults] setObject:object forKey:#"somename"];
Get Method:
NSMutableDictionary *dicCover = [[NSUserDefaults standardUserDefaults] valueForKey:#"somename"];
some time ,dictionary or array or not formatting right way we can use to achive your data like this to use NSUserdefault
Use Achive:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arrayUsers];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"somename"];
To get:
NSData *usersData = [[NSUserDefaults standardUserDefaults] valueForKey:#"somename"];
NSMutableArray *redirectionDic = [NSKeyedUnarchiver unarchiveObjectWithData:usersData];
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]
initWithSuiteName:keyChainGroup];
[myDefaults setObject:userInfo forKey:key];
Try this

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];

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.

Saving MKOverlayView array -> plist

I have an application that involves lots of MKOverlayViews. Every time one is added to the map, it is also added to an NSArray. When the user wishes to stop adding overlays, I would like for them to be able to save them, and be able to access them later. How can I store an array of MKOverlayViews into a plist, and then reload them back into a mapView later? Is this possible?
I'm attempting to use this code to take the MKPolylineViews from the array and add the corresponding MKPolylines to the map, but it crashes at the '[mapView addOverlay....' line.
Writing array to plist:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if(overlays)
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:overlays];
[defaults setObject:data forKey:#"theKey"];
[defaults synchronize];
}
Reading data from plist:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
for(MKPolylineView* a in arr)
[mapView addOverlay:a.polyline];
I'd look at archiving with NSArchiver or NSKeyedArchiver and then writing them out to disk. Probably better than trying to squeeze them into a plist somehow...