I have two Viewcontrollers in FirstVC i build 5 UITextField for registration ,this TextField value are stroed in dictionary finally the dictionary stored in NSUserdefault then in SecondVC i want to show this data
My problem is that each time when i add new discretionary in NSUserdefault The old one dictionary was replaced
i want data of all dictionary.
below is code of my FirstVC
-(void)btnReg
{
//data add in disctionary
for (int i=1; i<=5; i++)
{
UITextField *txtTemp=(UITextField *)[self.view viewWithTag:i];
[discRege setObject:[NSNumber numberWithInt:count] forKey:#"no"];
[discRege setObject:txtTemp.text forKey:[arraylblName objectAtIndex:i-1]];
}
//dictionary add in nsuserdefault
[[NSUserDefaults standardUserDefaults]setObject:discRege forKey:#"ABC"];
[[NSUserDefaults standardUserDefaults]synchronize];
//push to SecondVc
secondViewController *objSec=[[secondViewController alloc]init];
[self.navigationController pushViewController:objSec animated:YES];
[self.navigationController setNavigationBarHidden:false];
}
below is code of my SecondVC
ArratTemp =[[NSUserDefaults standardUserDefaults]objectForKey:#"ABC"] ;
if (!ArratTemp )
{
ArratTemp =[[NSMutableArray alloc]init];
}
else
{
ArratTemp = [[[NSUserDefaults standardUserDefaults]objectForKey:#"ABC"]mutableCopy];
}
NSLog(#"%#",ArratTemp);
Every time you are using the same key and replacing the existing dictionary object...
// Using the same key will overwrite the last saved dictionary.
[[NSUserDefaults standardUserDefaults] setObject:discRege forKey:#"ABC"];
Instead of storing it as a dictionary, store it as an array of dictionaries. Whenever you add new registration, fetch the saved array, add new dictionary object into it and update the userDefaults with that array.
mutableArray = [[[NSUserDefaults standardUserDefaults]objectForKey:#"ABC"] mutableCopy];
[mutableArray addObject:discReg];
[[NSUserDefaults standardUserDefaults] setObject:mutableArraay forKey:#"ABC"];
[[NSUserDefaults standardUserDefaults] synchronize];
Hope it helps.
You're overwriting the same disctionary every time.
You have two solutions :
Solution 1.
Store different dictionaries under different keys, not all under "ABC". So in your for loop can use the index (i) to have multiple entries, instead of just ABC every time. Here it's a simple matter you can resolve yourself. Make sure to not store everything under the same Key, and you'll find them ;) For example, you could save under [NSNumber numberWithInt:i]and then browse your NSUserDefaults for 0, 1, 2, 3... and so on. I recommend against this btw, solution 2 is the way to go.
Solution 2.
Store all your dictionaries in an array, and then store the array in the NSUserDefaults.
For that, simply create an NSMutableArray that you keep empty, then add dictionaries in it !
NSMutableArray dataArray = [[NSMutableArray alloc]init];
for (int i=1; i<=5; i++)
{
//Creating new dictionary
NSMutableDictionary *currentDict = [[NSMutableDictionary alloc]init];
//Getting the text we want
UITextField *txtTemp =(UITextField *)[self.view viewWithTag:i];
NSString *text = txtTemp.text;
//This is here because you had it
[currentDict setObject:[NSNumber numberWithInt:count] forKey:#"no"];
//All dictionaries will have key = name of the Label,
//but you could change it to something static, like
// "Content" for example. It'll be easier to find later
[currentDict setObject:text forKey:[arraylblName objectAtIndex:i-1]];
//Adding that newly formed dictionary to the mutable array.
[dataArray addObject:currentDict];
}
//Adding the array containing dictionaries to the NSUSerDefaults
[[NSUserDefaults standardUserDefaults]setObject:dataArray forKey:#"ABC"];
Note : I'm not exactly sure what you're doing with the dictionaries in the for loop, but since you didn't show the code, I'm guessing its' not part of the question. With my answer you have enough information to make some corrections if needed. All you need to remember is :
Create a dictionary per answer, and not one for all
Put each dictionary in the same array
Save the array (containing all the dictionaries)
Related
I am trying to save an array of objects into an NSUserDefault without success. When I log out the array before the attempt it is full of object. However, when I try to log out the NSUserDefault it is NULL. Can anyone see what I might be doing wrong? Thanks for any suggestions:
Items *myItems = [mutableFetchedObjects mutableCopy];
NSLog(#"my Items%#",myItems);//LOGS OUT LONG LIST OF ITEMS
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:myItems];
[currentDefaults setObject:data forKey:#"myItems"];
[currentDefaults synchronize];
Items *myRetrievedItems = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"myItems"] mutableCopy];
NSLog(#"my Retrieved Items%#",myRetrievedItems); //LOGS OUT AS NULL
As the other answers mentioned, it is because your array is not complying to the NSDictionary types (string, binary, bool, etc). Your members of array is of custom types therefore it cannot be saved. What you need to do is convert your array to binary first and then save it.
You have to unarchive your data first at the time of retrieving back. You are directly accessing the data. This won't work. You can do it the similar way you are archiving the data
NSData *dataObj = [currentDefaults objectForKey:#"myItems"];
Items *myRetrievedItems = [NSKeyedUnarchiver unarchiveObjectWithData:dataObj];
For more reference, you can consider this answer.
Hope this helps.
Thanks!
Your access value method is wrong.
You can get the array in following code:
Items *myRetrievedItems = [[[NSUserDefaults standardUserDefaults] objectForKey:#"myItems"] mutableCopy];
The following code is returning an exception with the following error message "mutating method sent to immutable object" when attempting to removeObjectForKey
NSMutableDictionary * storedIpDictionary = (NSMutableDictionary*)[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"dictDeviceIp"];
NSString *key = self.currentDeviceNameText.text;
NSString *ipAddressTemp = [storedIpDictionary objectForKey:key];
[storedIpDictionary removeObjectForKey:key]; <----Crashes here
storedIpDictionary[key] = ipAddressTemp;
Not sure what the issue is, perhaps it is due to retrieving the dictionary from a NSUserDefaults.
However the following code works without any issues.
NSMutableDictionary * storedIpDictionary = (NSMutableDictionary*)[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"dictDeviceIp"];
[storedIpDictionary removeAllObjects];
NSUserDefaults returns immutable objects, even if you put in mutable ones. You must call -mutableCopy on the returned value to get a mutable collection.
You cant just cast an NSDictionary to NSMutableDictinary thats not at all how casting works.
to remove a key from NSUserDefualts call removeObjectForKey on the NSUserDefaults instance itself.
if you really do want a dictionary for some other reason, then you must make a mutableCopy from the dictionary obtained by dictionaryForKey.
This is the code that eventually worked, I used some of the details provided from others above, but none had it completely explained.
- (void)cleanDictionary
{
NSMutableDictionary * storedIpDictionary = [[[NSUserDefaults standardUserDefaults] objectForKey: #"dictDeviceIp"] mutableCopy];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"dictDeviceIp"];
NSString *oldKey = self.currentDeviceNameText.text;
NSString *newKey = self.deviceNameChangeText.text;
NSString *ipAddressTemp = [storedIpDictionary objectForKey:oldKey];
// Make some change to the structure
[storedIpDictionary removeObjectForKey:oldKey]; // Remove object
storedIpDictionary[newKey] = ipAddressTemp; // Add object with new key
// Add it the whole thing back into NSUserDefaults
[[NSUserDefaults standardUserDefaults] setObject:storedIpDictionary forKey:#"dictDeviceIp"];
// Synchronize to ensure it's saved
[[NSUserDefaults standardUserDefaults] synchronize];
}
if you have on error NSMutableDictionary: mutating method sent to immutable object in Swift, make this step:
This is because you have assigned a NSUserDefault to NSMutableArray, when you take something NSUserDefault it returns you a NSArray not a NSMutableArray, so in this case you have to use a NSMutableArray Auxiliary .
see for Swift :
var Products:NSMutableArray = NSMutableArray()
override func viewDidAppear(animated: Bool) {
if let Produtos = NSUserDefaults.standardUserDefaults().valueForKey("Produtos") {
Products = Produtos as! NSMutableArray
}
}
func InsertProducts(productCode:String){
//COPY Products Atual for auxMutable
var auxMutable = Products.mutableCopy()
//Add object in auxMutable
auxMutable.addObjectsFromArray([productCode])
//in line back data to Array Products and make cast to NSMutableArray
Products = auxMutable as! NSMutableArray
//Refresh Data of NSUserDefaults
NSUserDefaults.standardUserDefaults().setObject(Products, forKey: "Produtos")
}
#IBAction func Bt_New_Product(sender: AnyObject) {
var ProductName:String = TXT_NameProduct.text
InsertProducts(ProductName)
}
This work for me!!!
i found same issue and found solution hope it will help some one.
arrayOfferId = defaults.objectForKey("offerId")?.mutableCopy() as! NSMutableArray
NSUserDefaults returns immutable objects, even if you put in mutable ones. You must call -mutableCopy on the returned value to get a mutable collection. so when you get value from NSUserDefault use mutableCopy()
[NSUserDefaults dictionaryForKey] returns an immutable dictionary (NSDictionary) and you cannot force it to be mutable by casting it to NSMutableDictionary.
Instead you must create the mutable dictionary using mutableCopy, overwrite the element and then re-assigning the dictionary back into NSUserDefaults:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *storedIpDictionary = [[userDefaults dictionaryForKey:#"dictDeviceIp"] mutableCopy];
NSString *key = self.currentDeviceNameText.text;
NSString *ipAddressTemp = [storedIpDictionary objectForKey:key];
// Don't need this line
//[storedIpDictionary removeObjectForKey:key];
storedIpDictionary[key] = ipAddressTemp;
[userDefaults setObject:storedIpDictionary
forKey:#"dictDeviceIp"];
I have an array which saves all the user inputs as an array of Strings using NSUserDefaults. In another view controller this array data can be viewed in a UITableView. Is there any way to delete the record in the array when I delete a row in the UITableView?
please refer the following for more detail.
https://stackoverflow.com/questions/32679088/tableview-nsinternalinconsistency-exception-error
Thanks
try like this in your tableview delete function
NSMutableArray *dataArray = [[NSUserDefaults standardUserDefaults] valueForKey:#"SavedArray"];
[dataArray removeObjectAtIndex:yourIndex];
[[NSUserDefaults standardUserDefaults ] setValue:dataArray forKey:#"SavedArray"];
[[NSUserDefaults standardUserDefaults]synchronize];
Using this code you will delete or resave your array in userdefaults
In your didSelect
NSMutableArray *yourArray=[[NSMutableArray alloc]init];
[yourArray removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
This is a three step process:
Step 1: Fetch & save your user details in a mutable array:
NSMutableArray *userDetailsArray = [[[NSUserDefaults standardUserDefaults] objectForKey:#"userDetails"] mutableCopy];
Step 2: Update your data array once user delete something. Use any of the below methods:
[userDetailsArray removeObject:<Your_Object>];
[userDetailsArray removeObjectAtIndex:<Your_Index>];
Step 3: Finally save them back in NSUserDefaults:
[[NSUserDefaults standardUserDefaults] setObject:userDetailsArray forKey:#"userDetails"];
[[NSUserDefaults standardUserDefaults] synchronize];
If you want to delete all NSUser defaults just use :-
NSUserDefaults.standardUserDefaults().removePersistentDomainForName(NSBundle.mainBundle().bundleIdentifier!)
Based on Apple documentation NSUserDefaults Class Reference "Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable"
My app allows users to create and several several arrays, from the media picker, saving each with a different user selected name. How can I allow the user to make a duplicate of one of the arrays and save under a different file name?
example list shows user created arrays
array1
array2
array3
Now the user wants to create a new array just like array3 but they will delete a few items rather than create an entire new array.
So I want the user to be able to make a copy of array3 naming it array4 and then make a be able to a few changes to array4 and save time.
Hope that makes some sense.
After the media picker selection of songs, this is my save playlist method:
- (void)savePlaylist:(MPMediaItemCollection *) mediaItemCollection
{
NSArray* items = [mediaItemCollection items];
if (items == nil)
{
return;
}
NSMutableArray* listToSave = [[NSMutableArray alloc] initWithCapacity:0];
for (MPMediaItem *song in items)
{
NSNumber *persistentId = [song valueForProperty:MPMediaItemPropertyPersistentID];
[listToSave addObject:persistentId];
}
//read playlist title
NSUserDefaults *defaults;
defaults = [NSUserDefaults standardUserDefaults];
NSString *thissongsList;
thissongsList = [defaults objectForKey:#"savetextkey"];
//save playlist
defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject: thissongsList forKey:#"savetextkey"];
[defaults synchronize];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject: listToSave];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:_songsList];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Asking to duplicate an array is fine, but we don't even know what language you're using. If you are using Objective-C, then all you have todo in order to copy an array is send the "copy" command on an array. Example below.
NSArray *myArray = [oldArray copy];
This is called a "shallow copy" which means it'll only copy the pointer references and not the actual objects. If you need to make brand new instances of the objects, then you'll need to adopt the NSCopying protocol in your objects, and override the copyWithZone method.
If you are using Swift then you'll basically do the same thing. To copy the array you'll use the code below.
var myArray = oldArray
Then use the same NSCopying protocol if you want to make a deep copy.
That's it, that is all you've got todo to copy an array.
Thanks
So, I have an application that I'm building which includes a checklist of 100 items.
I wish to create an array of bools which indicate whether or not an item is "checked", then save it to the device using NSUserDefaults so it can be loaded each time the app is run.
I understand by reading around that you cannot store bool values in NSArrays so I opted of a mutable array which holds strings #"YES" and #"NO"... I'm almost certain this is a bad way of doing it but I'm out of ideas.
I create my array like this:
boolArrayOfCheckList = [[NSMutableArray alloc] initWithCapacity:100];
for (NSInteger i = 0; i < 100; i++){
[boolArrayOfCheckList addObject:[NSString stringWithFormat:#"NO"]];
}
When an item is checked using an IBAction, it updates the array at the index associated with the button (this appears to be adding to the array instead of replacing the object at said index :( ...):
[boolArrayOfCheckList insertObject:[NSString stringWithFormat:#"YES"] atIndex:0];
Then save the array like this:
[[NSUserDefaults standardUserDefaults] setObject:boolArrayOfCheckList forKey:#"myBoolArray"];
When I reload the application, the ViewdidLoad loads the key:
NSMutableArray *boolArrayOfCheckList = (NSMutableArray *)[[NSUserDefaults standardUserDefaults] objectForKey:#"myBoolArray"];
and comparing the element like this and loading the items check/uncheck accordingly:
if([[boolArrayOfCheckList objectAtIndex:0] isEqualToString:#"YES"]) ... //do this
But I'm getting some funny results when I add strings and I'm having trouble loading the data again.
There must be a better more efficient way of storing a checklist in an array that can be saved/updated accordingly. How can this be done?
Thank you.
Update
Just noticed I was inserting instead of replacing, so that explains the array getting bigger instead of replacing the object at a specific index. Now doing this:
[boolArrayOfCheckList replaceObjectAtIndex:1 withObject:[NSString stringWithFormat:#"YES"]];
You can use the NSNumber BOOL #YES and #NO instead of an NSString of #"YES" and #"NO".
NSDictionary *test = #{#"key" : #YES};
To get the value:
BOOL keyBoolValue = [test[#"key"] boolValue];
NSLog(#"keyBoolValue: %i", keyBoolValue);
if (keyBoolValue == YES) {
NSLog(#"true:");
}
else {
NSLog(#"false:");
}
or
if ([test[#"key"] boolValue] == YES) { ...