NSUserDefaults overwriting new values with old - iphone

I have a bunch of userdefaults value that I use to load my UITableView in
-(void) prepareDisplay
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
table.dataSourceArray = [standardUserDefaults objectForKey:#"dataSource"];
}
-(void) viewDidLoad method
{
[self prepareDisplay];
}
and it works fine up to this point.
Then at a later point I change the userdefaults value and synchronize. Then I have to reload my table again. But before that I need to set the datasource array using the same
prepareDisplay () method.
Here I think that the instance of userdefaults that I created in my viewDidLoad earlier is overwriting or messing up with my userdefaults value and it calls up the old values again and not the newly set value.My newly set userdefaults value get overwritten with the old values. I have checked the plist file in the application sandbox after I do the userdefaults resetting and the values are reflected properly. But later, I don't how and when, they get overwritten with the old values. I am sure there is nothing I am doing explicitly to mess them up after resetting.
Can anybody help. Thanks

Actually you don't need an instance variable for NSUserDefaults because it is a singletone object. Avoid it. Additionally you may check the method - (BOOL)synchronize of the same object which Writes any modifications to the persistent domains to disk and updates all unmodified persistent domains to what is on disk.

Related

Storing complete class object into database in iPhone

I am new to this development.
I want to store complete object of a class into my database.
Actually I am creating application where user can add multiple views to parent view and want to save it, so that next time when user fetches it, he will get what ever he has saved i.e. views to parent view previously.
Any logic or suggestion on same will really be helpful,
Thanks in advance
Any object you want to save will need to conform to the NSCoder protocol. Keep in mind that if you have custom objects within your parent object that they to will need to conform to NSCoder. Add the following methods to your custom class(es).
- (id)initWithCoder:(NSCoder *)coder {
_inventory = [[coder decodeObjectForKey:#"inventory"] retain];
return self;
}
- (void)encodeWithCoder:(NSCoder *) encoder{
[encoder encodeObject:_inventory forKey:#"inventory"];
}
In the example above I want to encode a player's inventory. If the inventory contains custom objects (as opposed to a bunch of NSStrings for example) they'll also need their own NSCoder methods.
Below I turn it into something you can save out to NSUserDefaults. Adjust appropriately to store in a DB. Keep in mind if you want to send NSData over the wire to store in a DB you'll want to convert it to Base64 and possibly compress it.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData * encodedObject = [NSKeyedArchiver archivedDataWithRootObject:rootObject];
[defaults setObject:encodedObject forKey:kSaveArchiveKey];
[defaults synchronize];
To go the other way, you'll want to grab your NSData, do whatever magic on it as I described above (base64, compression) and unarchive.
PlayerInventory *inventory = [NSKeyedUnarchiver unarchiveObjectWithData:playerInventoryData]
You should choose between NSCoding and Core Data depending on your exact needs. See this post for more info: NSCoding VS Core data
You can store state(value of any attributes) of any object in database. You should use NSCoding.Example here

What's the best way to get a value from NSUserDefaults on app load and store it in a global variable?

What's the best way to get a value from NSUserDefaults on app load and store it in a global variable?
I could just hit [[NSUserDefaults standardUserDefaults] objectForKey:#"Theme"] every time I wanted to access the value stored, but it would hit the disk every time and that would be bad (I need the value for UITableView cells). What I'd like to do is store that value from it to a global variable on load, and then use that variable throughout the app.
What's the best way to do this? Obviously I can't make a constant because [[NSUserDefaults standardUserDefaults] objectForKey:#"Theme"] can't be compiled as a constant. How should I make a global variable for this? Is there any way to put it in the main.m or Prefix.pch file? I would hate to have to hit the App Delegate every time throughout my whole app.
"NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value." - NSUserDefaults Class Reference
However, if you really want to have this 'constant' (it won't be a true constant though) do something like this
*.pch:
extern NSString *themeString;
AppDelegate.m:
NSString *themeString = nil;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
themeString = [[[NSUserDefaults standardUserDefaults] objectForKey:#"Theme"] copy];
// ...
}

Object from NSUserDefaults releasing?

So I have a username saved in the UserDefaults. For some reason, I am experiencing some strange behavior.
I have a data controller that goes and fetches some data from the server based on the user name.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSLog(#"NSUserDefaults dump: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
userID = [prefs stringForKey:#"username"];
This works fine for the first few times, but after I do some random stuff and go back to try and reload the views, it crashes. It says:
-[CFString retain]: message sent to deallocated instance 0x4b18ff0
This is strange because it is stopping on the NSLog line. Has anyone seen this before or know why it may be happening??
How you defined your userID? If it's a property with a retain attribute you should call
self.userID = [prefs stringForKey:#"username"];
this way your string will be retained automatically. The string that is returned from stringForKey is autoreleased.
stringForKey returns an autorelease object which you aren't retaining, it's probably released as soon as that method finishes.
You need to retain that string either by doing so manually or using a property declaration with the retain setting.
And then you need to release it at some point (at least in dealloc)

When manually triggering a KVO event, can the change dictionary be amended?

I have a data model, composed mostly of an NSMutableArray 'contents' and NSMutableDictionary 'contentsByName'. I have ViewController objects that I wish to observe changes in the data model.
I have a property "count" on the model that returns the size of the array 'contents' and I can trigger a KVO change observation with willChange: and didChange:. So far, so good. However, the view-controllers are now aware that the model has changed, but do not know what's been added to it. Ideally, I need to put extra information into the change dictionary that's delivered to the observer.
Is this at all possible?
This is easily solvable by updating the model objects in a more granular way; however, built-in collections don't generate KVO notifications when their contents are modified, and will require some manual support.
If you want to generate notifications about changes to the array, use willChange:valuesAtIndexes:forKey: and didChange:valuesAtIndexes:forKey: whenever it's modified. When these methods are used, the change dictionary will contain an entry for NSKeyValueChangeIndexesKey, which reflects the indexes of insertion, deletion, or replacement.
If you want to generate notifications about changes to the dictionary, you can call willChangeValueForKey: and didChangeValueForKey: on the dictionary itself, like so:
- (void)addContent:(id)content {
NSString *key = [content name];
[self.contentsByName willChangeValueForKey:key];
[self.contentsByName setValue:content forKey:key];
[self.contentsByName didChangeValueForKey:key];
}
Any observer can also use NSKeyValueObservingOptionNew or NSKeyValueObservingOptionOld to receive the new or old values, respectively.

Core Data not saving changes to Transformable property

I am saving an NSMutableArray in a Transformable property in my Core Data store. I can create the entity properly with data in the NSMutableArray and then load it out of the property, and even make changes. When I go around my app and re-access it, my changes are saved. However when I reload the app, the changes have not saved in the core data store. Other changes to the entity - e.g. changing its title, which is saved as an NSString - are saved even when I quit and re-open the app.
I read in another StackOverflow question that Transformable attributes are not automatically notified of changes, and that I'd have to call "the appropriate setter before saving". However even using the actual setter functions - I have also tried calling didChangeValueForKey - the property is not saved properly. Any good ideas?
You must, as you note, "re-set" a transformable property:
id temp = [myManagedObject myTransformableAttribute];
//.. do something with temp
[myManagedObject setMyTransformableAttribute:temp];
There is no way that Core Data could appropriately monitor an arbitrary transformable object so that it could 'do the right thing' automatically.
Furthermore, you must be certain that you actually save the managed object context after you modify the transformable attribute:
NSError *error;
if(![[myManagedObject managedObjectContext] save:&error]) {
//present error
}
During a single run of the program, unsaved changes will appear visible because the managed object context keeps modified instances in memory. Without saving the context, however, those changes will not be persisted to disk.
I've noticed that you not only need to re-set the property. But you also need another instance. That is why it wasn't working with NSMutableArray
Transformable *copy = [managedObject.transformableProperty copy];
// do stuff
managedObject.transformableProperty = copy;