2

I've seen that NSUserDefaults do not allow objects other than Array, Dictionary, String, NSData, NSNumber, Bool, NSDate. But

  • Why it is not allowed to store other objects?
  • What if I need to store some properties as a single object? If I do it using dictionary, I've to write the keys somewhere which I've used to store the value. So, what could be the other alternatives.
  • What were the problems will arise if Apple allows the other objects also to store.
  • What if we use CoreData instead NSUserDefaults. I Know NSUserDefaults is globally available.
  • What is the best way to make a value available globally even after we relaunched the app if get terminated?

As suggested by @Hoa, previously I forgot mention NSCoding option also

  • What if we have many properties in a custom class, Do we need to encode and decode all of them using NSCoding methods?
Kara
  • 6,115
  • 16
  • 50
  • 57
Amit Singh
  • 2,698
  • 21
  • 49
  • Of course you can store Custom object with NSCoding method. https://blog.soff.es/archiving-objective-c-objects-with-nscoding – Duyen-Hoa Jun 29 '16 at 12:16
  • I think one of the best ex. is here - http://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults – Anupam Mishra Jun 29 '16 at 12:17

3 Answers3

3

You can save any object to a plist file as long as it is compliant with the NSCoding protocol.

You can use code similar to this:

+(id) readObjectFromFile:(NSString*) sFileName
{
    return [NSKeyedUnarchiver unarchiveObjectWithFile:sFileName];
}


+(bool) saveObject:(id <NSCoding>) anObject ToFile:(NSString*) sFileName
{
    NSData * data = [NSKeyedArchiver archivedDataWithRootObject:anObject];
    NSError * error;
    [data writeToFile:sFileName options:NSDataWritingAtomic error:&error];
    if (error)
        {
            NSLog(@"Save Cats Data error: %@", error.description);
            return NO;
        }
    return YES;
}

Swift Version:

func readObjectFromFile(sFileName: String) -> AnyObject {
   return NSKeyedUnarchiver.unarchiveObjectWithFile(sFileName)
}

func saveObject(anObject: AnyObject, ToFile sFileName: String) -> Bool {
    var data: NSData = NSKeyedArchiver.archivedDataWithRootObject(anObject)
    var error: NSError
    data.writeToFile(sFileName, options: NSDataWritingAtomic, error: error)
    if error != nil {
        print("Save Cats Data error: \(error.description)")
        return false
    }
    return true
}

To learn more about the NSCoding protocol you can read: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/

Arik Segal
  • 2,963
  • 2
  • 17
  • 29
0

The intention behind NSUserDefaults is to save contextual data relevant to the application state, for example saving the user's preferences, the state of the application when the user stopped using it (so you can return to that state when it fires up), login session data, etc..

Core Data is a more appropriate way to store persistent data, you can map your data model as you like and has a broader variety of options to save datatypes.

Whilst NSUserDefaults is available "everywhere", this should not be a turning point to decide if this is a better option for saving your data.

You can write a singleton class that serves as a data provider so that you can access your data in the same way you access the NSUserDefaults shared instance. You just need to keep in mind that this class or module should do only one thing, serve as an interface between your model and your implementation, so you do not store any objects in this class, just use it to pass over the requests to get and save data to CoreData.

This class could look something like this:

class CoreDataProvider {

    static let sharedInstance = SUProvider()

     let managedObjectContext : NSManagedObjectContext
     let sortDescriptor: NSSortDescriptor
     let fetchRequest: NSFetchRequest

     private init(){
         managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
         fetchRequest = NSFetchRequest(entityName: "MyObject")
         sortDescriptor = NSSortDescriptor (key:"objectAttribute", ascending:true)

         self.fetchRequest.sortDescriptors = [self.sortDescriptor]
     }

     func getSavedObjects() -> [MyObject]? {
        fetchRequest.sortDescriptors = [sortDescriptor]

        do {
            return try self.managedObjectContext.executeFetchRequest(fetchRequest) as? [MyObject]
        } catch {
            print("no records found")
        }
    }
}

Which you would use like this:

func getAllRecords() {
    let records = CoreDataProvider.sharedInstance.getSavedObjects()
    //- Do whatever you need to do
}
Daniel Ormeño
  • 2,743
  • 2
  • 25
  • 30
0

A temporary way to store object is to create json strings of your dictionaries or arrays. I have used it in some low scale apps. You can then store those string in NSUserDefault.., and when you need to use it, you can extract it, and you can use Object Mapper library that will automatically map the json data to object type.

example, you can create a function in your class extension that parses json data to your objects any time you need it.

I would suggest using the above method only for small scale apps. If you are going for high traffic/large scale app, you might wanna look into Core Data or even SQlite3..

Feel free to ask any question

Reference to Object Mapper library is here

Akshansh Thakur
  • 5,163
  • 2
  • 21
  • 38