How to store custom objects in NSUserDefaults

后端 未结 7 1580
悲&欢浪女
悲&欢浪女 2020-11-21 11:48

Alright, so I\'ve been doing some poking around, and I realize my problem, but I don\'t know how to fix it. I have made a custom class to hold some data. I make objects fo

相关标签:
7条回答
  • 2020-11-21 12:00

    Swift 4 introduced the Codable protocol which does all the magic for these kinds of tasks. Just conform your custom struct/class to it:

    struct Player: Codable {
      let name: String
      let life: Double
    }
    

    And for storing in the Defaults you can use the PropertyListEncoder/Decoder:

    let player = Player(name: "Jim", life: 3.14)
    UserDefaults.standard.set(try! PropertyListEncoder().encode(player), forKey: kPlayerDefaultsKey)
    
    let storedObject: Data = UserDefaults.standard.object(forKey: kPlayerDefaultsKey) as! Data
    let storedPlayer: Player = try! PropertyListDecoder().decode(Player.self, from: storedObject)
    

    It will work like that for arrays and other container classes of such objects too:

    try! PropertyListDecoder().decode([Player].self, from: storedArray)
    
    0 讨论(0)
  • 2020-11-21 12:01

    Synchronize the data/object that you have saved into NSUserDefaults

    -(void)saveCustomObject:(Player *)object
    { 
        NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
        NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
        [prefs setObject:myEncodedObject forKey:@"testing"];
        [prefs synchronize];
    }
    

    Hope this will help you. Thanks

    0 讨论(0)
  • 2020-11-21 12:04

    Swift 3

    class MyObject: NSObject, NSCoding  {
        let name : String
        let url : String
        let desc : String
    
        init(tuple : (String,String,String)){
            self.name = tuple.0
            self.url = tuple.1
            self.desc = tuple.2
        }
        func getName() -> String {
            return name
        }
        func getURL() -> String{
            return url
        }
        func getDescription() -> String {
            return desc
        }
        func getTuple() -> (String, String, String) {
            return (self.name,self.url,self.desc)
        }
    
        required init(coder aDecoder: NSCoder) {
            self.name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
            self.url = aDecoder.decodeObject(forKey: "url") as? String ?? ""
            self.desc = aDecoder.decodeObject(forKey: "desc") as? String ?? ""
        }
    
        func encode(with aCoder: NSCoder) {
            aCoder.encode(self.name, forKey: "name")
            aCoder.encode(self.url, forKey: "url")
            aCoder.encode(self.desc, forKey: "desc")
        }
        }
    

    to store and retrieve:

    func save() {
                let data  = NSKeyedArchiver.archivedData(withRootObject: object)
                UserDefaults.standard.set(data, forKey:"customData" )
            }
            func get() -> MyObject? {
                guard let data = UserDefaults.standard.object(forKey: "customData") as? Data else { return nil }
                return NSKeyedUnarchiver.unarchiveObject(with: data) as? MyObject
            }
    
    0 讨论(0)
  • 2020-11-21 12:16

    If anybody is looking for a swift version:

    1) Create a custom class for your data

    class customData: NSObject, NSCoding {
    let name : String
    let url : String
    let desc : String
    
    init(tuple : (String,String,String)){
        self.name = tuple.0
        self.url = tuple.1
        self.desc = tuple.2
    }
    func getName() -> String {
        return name
    }
    func getURL() -> String{
        return url
    }
    func getDescription() -> String {
        return desc
    }
    func getTuple() -> (String,String,String) {
        return (self.name,self.url,self.desc)
    }
    
    required init(coder aDecoder: NSCoder) {
        self.name = aDecoder.decodeObjectForKey("name") as! String
        self.url = aDecoder.decodeObjectForKey("url") as! String
        self.desc = aDecoder.decodeObjectForKey("desc") as! String
    }
    
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(self.name, forKey: "name")
        aCoder.encodeObject(self.url, forKey: "url")
        aCoder.encodeObject(self.desc, forKey: "desc")
    } 
    }
    

    2) To save data use following function:

    func saveData()
        {
            let data  = NSKeyedArchiver.archivedDataWithRootObject(custom)
            let defaults = NSUserDefaults.standardUserDefaults()
            defaults.setObject(data, forKey:"customArray" )
        }
    

    3) To retrieve:

    if let data = NSUserDefaults.standardUserDefaults().objectForKey("customArray") as? NSData
            {
                 custom = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [customData]
            }
    

    Note: Here I am saving and retrieving an array of the custom class objects.

    0 讨论(0)
  • 2020-11-21 12:20

    Taking @chrissr's answer and running with it, this code can be implemented into a nice category on NSUserDefaults to save and retrieve custom objects:

    @interface NSUserDefaults (NSUserDefaultsExtensions)
    
    - (void)saveCustomObject:(id<NSCoding>)object
                         key:(NSString *)key;
    - (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key;
    
    @end
    
    
    @implementation NSUserDefaults (NSUserDefaultsExtensions)
    
    
    - (void)saveCustomObject:(id<NSCoding>)object
                         key:(NSString *)key {
        NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
        [self setObject:encodedObject forKey:key];
        [self synchronize];
    
    }
    
    - (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key {
        NSData *encodedObject = [self objectForKey:key];
        id<NSCoding> object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
        return object;
    }
    
    @end
    

    Usage:

    [[NSUserDefaults standardUserDefaults] saveCustomObject:myObject key:@"myKey"];
    
    0 讨论(0)
  • On your Player class, implement the following two methods (substituting calls to encodeObject with something relevant to your own object):

    - (void)encodeWithCoder:(NSCoder *)encoder {
        //Encode properties, other class variables, etc
        [encoder encodeObject:self.question forKey:@"question"];
        [encoder encodeObject:self.categoryName forKey:@"category"];
        [encoder encodeObject:self.subCategoryName forKey:@"subcategory"];
    }
    
    - (id)initWithCoder:(NSCoder *)decoder {
        if((self = [super init])) {
            //decode properties, other class vars
            self.question = [decoder decodeObjectForKey:@"question"];
            self.categoryName = [decoder decodeObjectForKey:@"category"];
            self.subCategoryName = [decoder decodeObjectForKey:@"subcategory"];
        }
        return self;
    }
    

    Reading and writing from NSUserDefaults:

    - (void)saveCustomObject:(MyObject *)object key:(NSString *)key {
        NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:encodedObject forKey:key];
        [defaults synchronize];
    
    }
    
    - (MyObject *)loadCustomObjectWithKey:(NSString *)key {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSData *encodedObject = [defaults objectForKey:key];
        MyObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
        return object;
    }
    

    Code shamelessly borrowed from: saving class in nsuserdefaults

    0 讨论(0)
提交回复
热议问题