gpt4 book ai didi

ios - NSUserDefaults 和我自己的链表实现

转载 作者:行者123 更新时间:2023-11-30 12:09:35 24 4
gpt4 key购买 nike

我正在创建应用程序,我需要在其中获取最近 10 次搜索的列表并保存它(以在应用程序启动之间显示一致的信息)。

为此,我创建了链表(LinkedList 和 Node 类)的实现以及某种包装类,将其维护为最近 10 个字符串的列表。我使所有这 3 个类都符合 NSCoding 协议(protocol),并且当需要将其保存为 NSUserDefaults 时它就可以工作。不幸的是,当我尝试加载它时,应用程序崩溃并出现错误:

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'

这是所有 3 个类的代码:

类节点

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")
}
}

链表类

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")
}
}

最近的类(class)

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
}
}

问题出在哪里?

最佳答案

您收到的错误消息:

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'

表明NSKeyedUnarchiver 很难找到具有给定名称的类。正如您所看到的,您的类的 Objective-C 名称非常困惑(_TtGC26Informacje_o_organizacjach4NodeSS_),因为它使用了仅 Swift 的功能(在本例中为泛型)。事实是,据我所知,这种修改并不稳定,你需要一个存档格式中的类名,你可以保证将来不会改变。所以我要做的就是使用 @objc() 属性提供一个稳定的 Objective-C 名称,以确保类名保持不变。名称是什么并不重要,只要它是唯一的并且不会改变即可。

@objc(MyApp_Node) public class Node<S>: NSObject, NSCoding {

我不能保证这会解决问题,但它可能会解决问题,而且无论您是否要依赖 NSCoding,这都是您需要做的事情。

编辑:事实证明 @objc 不适用于具有泛型参数的类。所以答案很简单,NSCoding 支持和通用参数是互斥的。您将需要牺牲其中之一(幸运的是,Swift 4 有 Codable,您可以使用它来代替 NSCoding)。

关于ios - NSUserDefaults 和我自己的链表实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46245176/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com