Is NSUserDefaults the right choice for this app idea in swift - ios

I have a super simple app idea that I'm building out in order to get more practices at using Swift. I just want to ask if using NSUserDefaults is the most appropriate choice. All I will have is list of names with a number associated with each name that I will update (the number) from time to time. I was going to use a NSDictionary for the data.
I think Core Data is over kill for something like this.
I just wanted to get a 2nd opinion on my idea on how to save the data for this simple app.
Thanks

You can use NSUserDefault. But If want to store an array or dictionary you have to do some extra work. The documentation says:
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 can convert your NSDictionary to NSData, then save it to NSUserDefault.
// Convert the dictionary and store
var data = NSKeyedArchiver.archivedDataWithRootObject(yourDict)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: yourKey)
// Retrieving the dictionary
var savedData = NSUserDefaults.standardUserDefaults().dataForKey(yourKey)
var dict = NSKeyedUnarchiver.unarchiveObjectWithData(savedData)
Hope this helps.. :)

If it's just one NSDictionary that should be fine. NSUserDefaults is good for small things like that.
NSUserDefaults.standardUserDefaults().setObject(**YOUR DICTIONARY**, forKey: **YOUR KEY**)

Related

Edit NSUserDefaults Managed Configuration Dictionary

MDM Providers write to a dictionary which is retrievable using
NSUserDefaults.StandardUserDefaults.DictionaryForKey("com.apple.configuration.managed")
How can I programatically write key/value pairs to this dictionary?
Firstly retrieve the configuration dictionary:
NSMutableDictionary configDic = NSUserDefaults.StandardUserDefaults.DictionaryForKey("com.apple.configuration.managed").MutableCopy() as NSMutableDictionary;
Then you can modify this NSMutableDictionary like:
configDic["key1"] = (NSString)"value1";
At last write back to NSUserDefaults:
NSUserDefaults.StandardUserDefaults.SetValueForKey(configDic, (NSString)"com.apple.configuration.managed");
NSUserDefaults.StandardUserDefaults.Synchronize();
Because NSDictionary can't be modified after initialization, we need to convert it to NSMutableDictionary. If the value of configDic is type of NSDictionary(or NSArray), we also need to copy it deeply before we want to modify it.

Is it possible to save an NSManagedObject in NSUserDefaults?

I've having difficulty saving an NSManagedObject in userDefaults and I'd like to know a) should I be trying to do this or is this not an appropriate approach or b) if it is an appropriate approach, how can I get it to work?
I'm writing my app in Swift 2.3 and it has a few user default options, one of which is for a default "lift" (as in weightlifting, e.g. 'bench press', 'clean and jerk', 'incline bench press'). I'm actually converting them from an enum to a Core Data entity because every lift event that the user will be able to keep track of will be one of the available lifts types (for which I'll establish the appropriate relationship).
Here's the extension with the properties:
extension Lift {
#NSManaged var liftName: String
#NSManaged var type: NSSet
}
and the Lift entity with the things Xcode is complaining about:
class Lift: NSManagedObject, NSCoding {
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(liftName, forKey: "liftName")
} // Super.init isn't called on all paths before returning from initializer
required init(coder aDecoder: NSCoder) {
// Initialization of immutable variable was never used, etc...
let liftName = aDecoder.decodeObjectForKey("liftName") as! String
}
}
I've dealt with these types of errors before so my real concern is whether or not I'm headed down the wrong path.
I've read numerous threads tonight which have taught me that I'll need to encode an object (but not specifically an NSManagedObject) to save it then unencoded it when retrieving it and that my class must conform to NSCoding and what that protocol requires. But then I've seen threads that say NSManagedObjects should NOT be stored in userDefaults, but I don't know if that's true.
I've spent a few hours on this so before I go further, can/should this be done?
No, you should not store an NSManagedObject in NSUserDefaults. Core Data is an object persistence technology, so it doesn't make sense to try and persist an NSManagedObject in some other format.
There are few alternatives you can use:
You could simply store the name of the lift in your user defaults and then query for this to get the object back from Core Data. This may not work for you if lift names aren't unique
You can add an identifier attribute to your Lift entity and store something like a UUID string in that attribute; You can then store the same string in UserDefaults. This will ensure one object is selected uniquely.
You can add a new boolean attribute to your Lift entity default and again use a query to retrieve it; You would need to ensure you only set the value to true on one lift at a time.
You can use managedObject.objectId.uriRepresentation to get a URL that you can store as a string and then use to retrieve the object later. This is probably the most complex solution and I would suggest you try one of the other options.
No, You cannot do this. You cannot save Core Data objects in User Defaults. It can only save in its DB.
This two are totally two different things. NSUserDefault stores the light pieces of data where NSManagedObject stores the light or heavy amount of data and is very fast than NSUserDefault for storing and retrieving purposes.
NSManagedObject -> NSManagedObject link to coredata.
You should it to store a large list of elements. As far your last question, there is nothing preventing you from using both Core Data and a backend to store your data. In fact, there are frameworks out there to facilitate exactly this.
NSUserDefaults -> NSUserDefaults is a class that allows simple storage of different data types. It is ideal for small bits of information you need to persist between app launches or device restarts. NSUserDefaults is not sufficient and reliable to store and query the huge amount of data. It's suggestable if you'll have a backend (database on the server) to store events and their invitees to persist consistency of user's information (if user logged in back to your app from other app supportive device then he'll get all information he stored).
NSUserDefaults supports the following data types:
NSString, NSNumber, NSDate, NSArray, NSDictionary and NSData
Hope it will help you.
Storable Types in NSUserDefaults.
The NSUserDefaults class acts very much like something called a Property List (aka plist). It may be just a fancy interface for a plist, or it may be more, I’m not entirely sure. Nonetheless, plists are limited in what kind of objects they can store. The six types plists can store are:
NSData
NSString
NSNumber
NSDate
NSArray
NSDictionary
So,you need to use in NSKeyedArchiver.
let ArchvieArr = NSMutableArray()
ArchvieArr.addObject(NSKeyedArchiver.archivedDataWithRootObject(LiftObj)).
NSUserDefaults.standardUserDefaults().setObject(ArchvieArr, forKey: "savedArray")

How to store a NSManagedObjectID persistently?

To avoid being an XY problem, here's some background:
My app allows users to create and save a lot of settings kinda like the Xcode's fonts and colors chooser:
This is because there are a lot of things that users can set. It would be easier to just tap on a saved setting instead of setting all those things again.
I used Core Data to store the settings the user saved. Each setting the user created is an instance of an NSManagedObject subclass. And now I need to store the selected setting persistently so that the user will have the same setting selected as before when the app reopens.
My first thought was to store the NSManagedObject subclass instance in NSUserDefaults. But according to the docs, I can't store it unless I convert it to NSData:
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.
Then I tried storing the objectID of the NSManagedObject subclass instance. I see that there is a URIRepresentation() method that returns an NSURL. So I thought this would work:
NSData(contentsOfURL: selectedOption!.objectID.URIRepresentation())
But the initializer failed somehow.
Now I realize that this is a stupid idea because even if I can convert it to NSData, I can't convert NSData back to NSManagedObjectID!
According to this question, the OP seems to be able to store the object id:
I store the selected theme objectID in NSUserDefaults so that when the app restarts, the selected theme will still be intact.
How can I do that?
NSUserDefaults has "convenience methods"
public func setURL(url: NSURL?, forKey defaultName: String)
public func URLForKey(defaultName: String) -> NSURL?
which allow to store and retrieve a NSURL like the one obtained
by URIRepresentation(). The conversion to and from NSData
is handled transparently. From the documentation:
When an NSURL is stored using -[NSUserDefaults setURL:forKey:], some adjustments are made:
Any non-file URL is written by calling +[NSKeyedArchiver archivedDataWithRootObject:] using the NSURL instance as the root
object.
...
When an NSURL is read using -[NSUserDefaults URLForKey:], the following logic is used:
If the value for the key is an NSData, the NSData is used as the argument to +[NSKeyedUnarchiver unarchiveObjectWithData:]. If the NSData can be unarchived as an NSURL, the NSURL is returned otherwise nil is returned.
...
So saving the managed object ID is simply done as
NSUserDefaults.standardUserDefaults().setURL(object.objectID.URIRepresentation(),
forKey: "selected")
and retrieving the object ID and the object for example like this:
if let url = NSUserDefaults.standardUserDefaults().URLForKey("selected"),
let oid = context.persistentStoreCoordinator!.managedObjectIDForURIRepresentation(url),
let object = try? context.existingObjectWithID(oid) {
print(object)
// ...
}
For alternative approaches of saving the selected settings, see the above comment.

Save a function to NSUserDefaults in Swift

So, I was wondering if it is possible to save a function to user defaults using Swift. For a string, for example, I would do this:
var inputData = "Hi"
NSUserDefaults.standardUserDefaults.setValueForKey(inputData, forKey: "data")
Then to save it do a variable, I would say:
var gotData = NSUserDefaults.standardUserDefaults.valueForKey("data")!
Now, my question is, if it is possible to save a function to user defaults. For example:
var inputData = func helloWorld(){println("Hello World!")}
Is it possible to then call that function that was saved to user defaults by doing something similar to .valueForKey ?
Any help is valued! Thanks a lot in advance!
You cannot save a function to NSUserDefaults. From the NSUserDefaults Class Reference:
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.
A function is not any of the supported types, and as far as I know you cannot archive a function either.

Store an array of UIViews in NSUserDefaults

I'm trying to add an array of uiviews to NSDefault but it doesn't seem to be keep the array. Does any one know why? I also tried to store each view in nsvalue before storing it in nsdefault which still didn't work.
NSArray *arr = [[NSArray alloc] initWithObjects:[NSValue valueWithNonretainedObject:myView], nil]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:arr forKey:#"myKey"];
NSArray *resultArray = [defaults objectForKey:#"myKey"];
and resultArray is nil!
Thanks
the reason why I'm trying to do this is because these are the header views of my uitableview. Since it takes time to create them I wanted to create them only once and store them for future access.
From the docs for NSUserDefaults:
The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData. For more details, see Preferences and Settings Programming Guide.
If you want to put a UIView (why?) in NSUserDefaults, you need to archive it first into an NSData object.
But you need to ask yourself why you want to put a view in NSUserDefaults. You should only be putting bits of data in NSUserDefaults. Views display data. It's easy to redisplay a view once you have the data back. Consider just putting some needed data in NSUserDefaults.
Are you sure you want to do that? It is definitely better to store an array of models to the data base or some file and recreate views from them when needed.
A ha! You are not the first person to face this issue. I've not had this type of issue myself but, in the link below, is a blog with code that allows you to cache and re-use your views. Then you would only need to re-create the views when you launch. Example code:
Cache UIViews for re-use in tableview

Resources