Je crée l'application, où j'ai besoin d'avoir une liste de 10 recherches récentes et de la sauvegarder (pour afficher des informations cohérentes entre les lancements d'applications).NSUserDefaults et ma propre implémentation de liste chaînée
Pour cela, j'ai créé mon implémentation de liste chaînée (classes LinkedList et Node) et une sorte de classe wrapper qui maintient la liste des 10 dernières chaînes. J'ai fait en sorte que toutes ces 3 classes soient conformes au protocole NSCoding et cela fonctionne quand il est temps de l'enregistrer en tant que NSUserDefaults. Malheureusement, lorsque je tente de le charger, l'application se bloque avec l'erreur:
Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (_TtGC26Informacje_o_organizacjach4NodeSS_) for key (head); the class may be defined in source code or a library that is not linked'
C'est le code de tous les 3 classes:
classe Node
public class Node<T>: NSObject, NSCoding {
var value: T
var next: Node<T>?
var previous: Node<T>?
init(value: T) {
self.value = value
}
public required init(coder aDecoder: NSCoder) {
value = aDecoder.decodeObject(forKey: "value") as! T
next = aDecoder.decodeObject(forKey: "next") as? Node<T>
previous = aDecoder.decodeObject(forKey: "previous") as? Node<T>
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(value, forKey: "value")
aCoder.encode(next, forKey: "next")
aCoder.encode(previous, forKey: "previous")
}
}
classe LinkedList
public class LinkedList<T>: NSObject, NSCoding {
fileprivate var head: Node<T>?
private var tail: Node<T>?
override init() {
head = nil
tail = nil
}
public var isEmpty: Bool {
return head == nil
}
public var first: Node<T>? {
return head
}
public var last: Node<T>? {
return tail
}
public var count: Int {
var node = head
var count = 0
while node != nil {
count = count + 1
node = node?.next
}
return count
}
public func removeLast() {
if let lastNode = last {
remove(node: lastNode)
}
}
public func appendFirst(value: T) {
let newNode = Node(value: value)
if let headNode = head {
headNode.previous = newNode
newNode.next = headNode
} else {
tail = newNode
}
head = newNode
}
public func append(value: T) {
let newNode = Node(value: value)
if let tailNode = tail {
newNode.previous = tailNode
tailNode.next = newNode
} else {
head = newNode
}
tail = newNode
}
public func nodeAt(index: Int) -> Node<T>? {
if index >= 0 {
var node = head
var i = index
while node != nil {
if i == 0 { return node }
i -= 1
node = node!.next
}
}
return nil
}
public func removeAll() {
head = nil
tail = nil
}
public func remove(node: Node<T>) -> T {
let prev = node.previous
let next = node.next
if let prev = prev {
prev.next = next
} else {
head = next
}
next?.previous = prev
if next == nil {
tail = prev
}
node.previous = nil
node.next = nil
return node.value
}
public required init?(coder aDecoder: NSCoder) {
head = aDecoder.decodeObject(forKey: "head") as? Node<T>
tail = aDecoder.decodeObject(forKey: "tail") as? Node<T>
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(head, forKey: "head")
aCoder.encode(tail, forKey: "tail")
}
}
classe Recents
public class Recents: NSObject, NSCoding {
fileprivate var list: LinkedList<String>
override init() {
list = LinkedList<String>()
}
public func enqueue(_ element: String) {
if let node = search(for: element) {
list.remove(node: node)
} else {
if list.count >= 10 {
list.removeLast()
}
}
list.appendFirst(value: element)
}
func search(for value: String) -> Node<String>? {
var curr = list.first
while curr != nil {
if curr?.value == value {
return curr
}
curr = curr?.next
}
return nil
}
public func count() -> Int {
return list.count
}
public func nodeAt(index: Int) -> String {
return list.nodeAt(index: index)!.value
}
public var isEmpty: Bool {
return list.isEmpty
}
public required init(coder aDecoder: NSCoder) {
list = aDecoder.decodeObject(forKey: "list") as! LinkedList<String>
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(list, forKey: "list")
}
}
I use this code to load and save data into NSUserDefaults:
func saveRecents() {
let savedData = NSKeyedArchiver.archivedData(withRootObject: recents)
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "recents")
}
func loadRecents() {
let defaults = UserDefaults.standard
if let savedRecents = defaults.object(forKey: "recents") as? Data {
recents = NSKeyedUnarchiver.unarchiveObject(with: savedRecents) as! Recents
}
}
Où est le problème?
Pourquoi ne pas simplement utiliser un tableau? – nathan