Search code examples
iosswiftnscodingnskeyedarchivernskeyedunarchiver

Load archived value from NSUserDefaults if it doesn't exist by overriding getter


I'm trying to add a fallback function to load an archived copy of a class if the property isn't set.

I've got the setter working fine so that it stores the value (and all of the NSCoding is working as expected), but if I try to reference this anywhere else, instead of using the actual variable property, it's always loading from NSUserDefaults.

Here's what I've got so far:

public var currentUser: User? {
    get {
        var user = self.currentUser
        // ^ this totally blows it up
        if (user == nil) {
            user = User.init(name: "") as? User
            if let data = NSUserDefaults.standardUserDefaults().objectForKey("currentUser") as? NSData {
                let unarc = NSKeyedUnarchiver(forReadingWithData: data)
                user = unarc.decodeObjectForKey("root") as? User
            }
        }
        return user
    }
    set(value) {
        self.currentUser = value
        NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(value!), forKey: "currentUser")
    }
}

Solution

  • What is happening with your code, is calling self.currentUser inside self.currentUser's getter. When you specify a custom getter for a computed property, you don't actually have storage for that instance, i.e. the value isn't saved, rather always computed. What you need is another instance property, which can be private, say _currentUser where you actually save the value, and which you check in you custom getter.

    
    private var _currentUser: User?
    public var currentUser: User? {
        get {
            if (_currentUser == nil) {
                _currentUser = User.init(name: "") as? User
                if let data = NSUserDefaults.standardUserDefaults().objectForKey("currentUser") as? NSData {
                    let unarc = NSKeyedUnarchiver(forReadingWithData: data)
                    _currentUser = unarc.decodeObjectForKey("root") as? User
                }
            }
            return _currentUser
        }
        set(value) {
            _currentUser = value
            NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(value!), forKey: "currentUser")
        }
    }