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...
Related
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
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
So I'm a bit dismayed that Apple has replaced a transparent, easy-to-handle NSUInteger with an HKQueryAnchor but has not provided an easy way to persist that HKQueryAnchor. Has anyone found a good way to do this with NSUserDefaults? The only persistence method I have seen is an archiver to a local file, but my app persists everything in NSUserDefaults, and I'd like to keep it that way if possible. Is there a reliable way to store an HKQueryAnchor this way?
You can convert it to NSData using NSKeyedArchiver and store that in the user defaults.
To store:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:anchor];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"AnchorData"];
To retrieve:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"AnchorData"];
HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data];
[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.
I am confused by the memory management in this scenario.
In my app user makes periodic input inside UITextField tf and the typed strings (NSString*) are stored as elements of a MSMutableArray *arr through addObject. The stored collection is displayed inside a UITableView. My app can go into bkgr and is periodically awakened by push notifications. As I understand it, the data stored in arr can be lost while my app is non-active and, to preserve it, I need to do archive/restore.
My archive/restore are using
NSUserDefaults*prefs;
[prefs setObjectForKey:x forKey:key]
to archive and
[prefs objectForKey:key]
to restore every item of arr.
Question1: I think that to prevent the memory leak I need to do [arr release]
Do I also need to do a release on every object which I have added to arr or, since I did not allocate the NSString for tf, it will be done for me automatically?
Question2: in restore I start with something like arr=[[NSMutableArray alloc] initWithObjects:nil]; before I can read and add archived items back to arr. I think that [prefs objectForKey:key] is released as soon as I leave the scope in which it was read - thus I need something like retain to keep it in arr. Would this schema work in the next archive/restore cycle due to another app deep sleep?
Is there a cleaner way of achieving the same?
Thanks.
Victor
Adding objects to an NSArray causes the NSArray to retain each object.
So in a case where you are instantiating objects, then adding them to an array, those objects do not need to be further retained:
// saving strings inside an array, then array to the NSUserDefaults
NSString *string1 = #"My String 1";
NSString *string2 = #"My String 1";
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:10];
[arr addObject:string1];
[arr addObject:string2];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];;
[prefs setObject:arr forKey:#"MyArray"];
[arr release];
Then to restore the entire array from prefs:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSArray *array = [prefs objectForKey:#"MyArray"];
Alternately, to save strings under separate keys, it would be something like this:
[prefs setObject:[arr objectAtIndex:0] forKey:#"MyFirstStringKey"];
[prefs setObject:[arr objectAtIndex:1] forKey:#"MySecondStringKey"];
For the restore, you will also just add the items to the array, no retain required:
// assuming this time several keys added to an array
// also note using autoreleased version of array - much easier
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:10];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];;
[arr addObject:[prefs objectForKey:#"MyFirstStringKey"]];
[arr addObject:[prefs objectForKey:#"MySecondStringKey"]];
// then assign arr or use it otherwise
Also easier still is to use a non-mutable array and instantiate the array with the list of objects you want to have on the array:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];;
NSArray *arr = [NSArray arrayWithObjects:[prefs objectForKey:#"MyFirstStringKey"], [prefs objectForKey:#"MySecondStringKey"], nil];