Lucas Haas
Lucas Haas

Reputation: 341

Issues with userdefaults usage swift 3

I just started learning Swift so the level of this question may be obvious enough for you, however, I simply can't understand what to do.

I "created" a simple app which allows you to add logs of your day. Each cell stores the time you added, a custom icon that changes depending on the time, and, the log text itself (simple text).

Everything works fine. But, as I didn't know about the "Userdefaults" stuff, the clock resets every time I kill the app.

I read many articles about Userdefaults but I have no idea what to do to keep saving my data even when I kill the app.

Here's what I tried to do:

class ToDoItem: NSObject, NSCoding {


var title: String
var date: String
var type: String!

public init(title: String, date: String, type: String) {

    self.title = title
    self.date = date
    self.type = type

}

required init?(coder aDecoder: NSCoder)
{
    // Try to unserialize the "title" variable
    if let title = aDecoder.decodeObject(forKey: "title") as? String
    {
        self.title = title
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .none
        dateFormatter.timeStyle = .short
        self.date = dateFormatter.string(from: Date())

        let hour = NSCalendar.current.component(.hour, from: Date())
        var tempType = ""
        switch hour {
        case 5..<9: tempType = "morning_1"
        case 6..<12: tempType = "morning_2"
        case 12: tempType = "noon_1"
        case 13..<16: tempType = "afternoon_1"
        case 16..<20: tempType = "dusk_1"
        case 20..<23: tempType = "evening_1"
        case 23..<00: tempType = "midnight_1"
        default: tempType = "morning_1"


        }

        self.type = tempType

    }



    else
    {
        // There were no objects encoded with the key "title",
        // so that's an error.
        return nil
    }

    let userDefaults = UserDefaults.standard
    userDefaults.set(true, forKey: "title")

}

func encode(with aCoder: NSCoder)
{
    // Store the objects into the coder object
    aCoder.encode(self.title, forKey: "title")

    let defaults = UserDefaults.standard
    defaults.set(false, forKey: "title")


}

}

extension Collection where Iterator.Element == ToDoItem
{
    // Builds the persistence URL. This is a location inside
    // the "Application Support" directory for the App.
    private static func persistencePath() -> URL?
    {
        let url = try? FileManager.default.url(
            for: .applicationSupportDirectory,
            in: .userDomainMask,
            appropriateFor: nil,
            create: true)

        return url?.appendingPathComponent("todoitems.bin")
    }

    // Write the array to persistence
    func writeToPersistence() throws
    {
        if let url = Self.persistencePath(), let array = self as? NSArray
        {
            let data = NSKeyedArchiver.archivedData(withRootObject: array)
            try data.write(to: url)
        }
        else
        {
            throw NSError(domain: "com.example.MyToDo", code: 10, userInfo: nil)
        }
    }

    // Read the array from persistence
    static func readFromPersistence() throws -> [ToDoItem]
    {
        if let url = persistencePath(), let data = (try Data(contentsOf: url) as Data?)
        {
            if let array = NSKeyedUnarchiver.unarchiveObject(with: data) as? [ToDoItem]
            {
                return array
            }
            else
            {
                throw NSError(domain: "com.example.MyToDo", code: 11, userInfo: nil)
            }
        }
        else
        {
            throw NSError(domain: "com.example.MyToDo", code: 12, userInfo: nil)
        }
    }
}

can anyone help me or at least point what I have to do? thank you!

Upvotes: 0

Views: 220

Answers (1)

deadbeef
deadbeef

Reputation: 5563

You're using NSKeyedArchiver and NSKeyedUnarchiver which is a different mechanism than UserDefaults. Both are perfectly valid, but you have to pick one, they don't work together.

Here you are archiving and unarchiving an array of ToDoItem. For this to work, ToDoItem needs to be archivable, meaning it must implement the NSCoding protocol, which is:

public protocol NSCoding {
    public func encode(with aCoder: NSCoder)
    public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER
}

All the properties that you want to save must be added to/extracted from the NSCoder object. Here is an example:

class ToDoItem: NSObject, NSCoding
{
    var title: String
    var date: Date

    required init?(coder aDecoder: NSCoder)
    {
        guard let title = aDecoder.decodeObject(forKey: "title") as? String else {
            return nil
        }
        guard let date = aDecoder.decodeObject(forKey: "date") as? Date else {
            return nil
        }
        self.title = title
        self.date = date
    }

    func encode(with aCoder: NSCoder)
    {
        aCoder.encode(self.title, forKey: "title")
        aCoder.encode(self.date, forKey: "date")
    }
}

Upvotes: 2

Related Questions