-1

How can I save my struct with NSCoding so that it doesn´t change even if the user closes the app? I would appreciate it if you could also show me how to implement the missing code correctly.

UPDATE with two new functions below: Here is my code:

    struct RandomItems: Codable
{
    var items : [String]
    var seen  = 0

    init(items:[String], seen: Int)
    {
        self.items = items
        self.seen = seen
    }

    init(_ items:[String])
    { self.init(items: items, seen: 0) }


    mutating func next() -> String
    {
        let index = Int(arc4random_uniform(UInt32(items.count - seen)))
        let item  = items.remove(at:index)
        items.append(item)
        seen = (seen + 1) % items.count
        return item
    }
    func toPropertyList() -> [String: Any] {
        return [
            "items": items,
            "seen": seen
        ]
    }


    }





override func viewWillDisappear(_ animated: Bool) {
    UserDefaults.standard.set(try? PropertyListEncoder().encode(quotes), forKey:"quote2")
}

override func viewDidAppear(_ animated: Bool) {
     if let data = UserDefaults.standard.value(forKey:"quote2") as? Data {
        let quote3 = try? PropertyListDecoder().decode(Array<RandomItems>.self, from: data)
    }

}




  }


extension QuotesViewController.RandomItems {
init?(propertyList: [String: Any]) {
    return nil
}

}

How can I make sure the whole Array is covered here?

Joy Lucas
  • 61
  • 1
  • 10
  • You need to make it a class. You will need also to subclass NSObject and make it conforms to NSCoding – Leo Dabus Oct 18 '17 at 17:43
  • 2
    Possible duplicate of [Save struct in class to NSUserDefaults using Swift](https://stackoverflow.com/questions/25546716/save-struct-in-class-to-nsuserdefaults-using-swift) – TNguyen Oct 18 '17 at 17:53

1 Answers1

7

For structs you should be using the new Codable protocol. It is available since swift 4 and is highly recommended.

struct RandomItems: Codable
{
    var items: [String]
    var seen = 0
}

extension RandomItems {
     init?(propertyList: [String: Any]) {
           ...
     }
}

// Example usage
let a = RandomItems(items: ["hello"], seen: 2)
let data: Data = try! JSONEncoder().encode(a)
UserDefaults.standard.set(data, forKey: "MyKey") // Save data to disk
// some time passes
let data2: Data = UserDefaults.standard.data(forKey: "MyKey")! // fetch data from disk
let b = try! JSONDecoder().decode(RandomItems.self, from: data2)

Update

It looks like the Original Poster is nesting the struct inside of another class. Here is another example where there struct is nested.

class QuotesViewController: UIViewController {

    struct RandomItems: Codable
    {
        var items: [String]
        var seen = 0
    }
}

extension QuotesViewController.RandomItems {
    init(_ items:[String])
        { self.items = items }

    init?(propertyList: [String: Any]) {
        guard let items = propertyList["items"] as? [String] else { return nil }
        guard let seen = propertyList["seen"] as? Int else { return nil }
        self.items = items
        self.seen = seen
    }
}

// example usage
let a = QuotesViewController.RandomItems(items: ["hello"], seen: 2)
let data: Data = try! JSONEncoder().encode(a)
UserDefaults.standard.set(data, forKey: "MyKey") // Save data to disk
// some time passes
let data2: Data = UserDefaults.standard.data(forKey: "MyKey")! // fetch data from disk
let b = try! JSONDecoder().decode(QuotesViewController.RandomItems.self, from: data2)
DerrickHo328
  • 4,664
  • 7
  • 29
  • 50