我有一个自定义System
对象,该对象具有一个expenses
变量(类型为[Int : (String, Double)]
),该变量存储在UserDefaults中。检索它之后,如果用户想向expenses
添加一些内容,我将覆盖旧的UserDefaults
值。
以下是用于存储值的代码:
class System: NSObject, NSCoding {
var expenses: [Int : (String, Double)] = [0: ("", 0.0)]
override init() {
self.expenses = [:]
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.expenses, forKey: "expenses") //Error occurs here
}
required init?(coder aDecoder: NSCoder) {
if let expenses = aDecoder.decodeObject(forKey: "expenses") as? [Int : (String, Double)] {
self.expenses = expenses
}
}
}
extension UserDefaults {
class func save(_ object: Any, withKey key: String) {
let data = NSKeyedArchiver.archivedData(withRootObject: object)
UserDefaults.standard.set(data, forKey: key)
}
class func data(forKey key: String) -> System? {
if let data = UserDefaults.standard.value(forKey: key) as? Data{
return NSKeyedUnarchiver.unarchiveObject(with: data) as? System
}
return nil
}
}
这是用于检索并添加到数组的代码:
class Expenses_TVC: UITableViewController {
var expenses: [Int: (String, Double)] = [:] {
didSet {
let s = System()
s.expenses = self.expenses //This line provoques the error
UserDefaults.save(s, withKey: "System")
self.tableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.isFirstLaunch() {
UserDefaults.save(System(), withKey: "System")
}
}
@IBAction func addExpense(_ sender: Any) {
expenses[expenses.count] = ("", Double(expenses.count))
}
}
当我尝试增加费用时,会发生错误:
App[10616:392547] -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x60400046a9c0
App[10616:392547] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x60400046a9c0'
*** First throw call stack:
(
0 CoreFoundation 0x0000000110ac21cb __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010feddf41 objc_exception_throw + 48
2 CoreFoundation 0x0000000110b42914 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x0000000110a45178 ___forwarding___ + 1432
4 CoreFoundation 0x0000000110a44b58 _CF_forwarding_prep_0 + 120
5 Foundation 0x000000010f9281aa _encodeObject + 1200
6 Foundation 0x000000010f9296bc -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 439
7 Foundation 0x000000010f9341f4 -[NSDictionary(NSDictionary) encodeWithCoder:] + 951
8 Foundation 0x000000010f9281aa _encodeObject + 1200
9 My Budget 0x000000010f5bd28c _T09My_Budget6SystemC6encodeySo7NSCoderC4with_tF + 172
10 My Budget 0x000000010f5bd2ec _T09My_Budget6SystemC6encodeySo7NSCoderC4with_tFTo + 60
11 Foundation 0x000000010f9281aa _encodeObject + 1200
12 Foundation 0x000000010f95b09b +[NSKeyedArchiver archivedDataWithRootObject:] + 156
13 My Budget 0x000000010f5bdd4a _T0So12UserDefaultsC9My_BudgetE4saveyyp_SS7withKeytFZ + 330
14 My Budget 0x000000010f5c0801 _T09My_Budget12Expenses_TVCC8expensess10DictionaryVySiSS_SdtGfW + 257
15 My Budget 0x000000010f5c0a68 _T09My_Budget12Expenses_TVCC8expensess10DictionaryVySiSS_SdtGfs + 232
16 My Budget 0x000000010f5c0aa2 _T09My_Budget12Expenses_TVCC8expensess10DictionaryVySiSS_SdtGfmytfU_ + 18
17 My Budget 0x000000010f5c1bde _T09My_Budget12Expenses_TVCC10addExpenseyypF + 542
18 My Budget 0x000000010f5c1c48 _T09My_Budget12Expenses_TVCC10addExpenseyypFTo + 72
19 UIKit 0x0000000110f3e9bd -[UIApplication sendAction:to:from:forEvent:] + 83
20 UIKit 0x000000011193253f __45-[_UIButtonBarTargetAction _invoke:forEvent:]_block_invoke + 154
21 UIKit 0x0000000111932470 -[_UIButtonBarTargetAction _invoke:forEvent:] + 181
22 UIKit 0x0000000110f3e9bd -[UIApplication sendAction:to:from:forEvent:] + 83
23 UIKit 0x00000001110b5183 -[UIControl sendAction:to:forEvent:] + 67
24 UIKit 0x00000001110b54a0 -[UIControl _sendActionsForEvents:withEvent:] + 450
25 UIKit 0x00000001110b43cd -[UIControl touchesEnded:withEvent:] + 618
26 UIKit 0x0000000110fb2d4f -[UIWindow _sendTouchesForEvent:] + 2807
27 UIKit 0x0000000110fb4472 -[UIWindow sendEvent:] + 4124
28 UIKit 0x0000000110f59802 -[UIApplication sendEvent:] + 352
29 UIKit 0x000000011188ba50 __dispatchPreprocessedEventFromEventQueue + 2809
30 UIKit 0x000000011188e5b7 __handleEventQueueInternal + 5957
31 CoreFoundation 0x0000000110a652b1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
32 CoreFoundation 0x0000000110b04d31 __CFRunLoopDoSource0 + 81
33 CoreFoundation 0x0000000110a49c19 __CFRunLoopDoSources0 + 185
34 CoreFoundation 0x0000000110a491ff __CFRunLoopRun + 1279
35 CoreFoundation 0x0000000110a48a89 CFRunLoopRunSpecific + 409
36 GraphicsServices 0x00000001165769c6 GSEventRunModal + 62
37 UIKit 0x0000000110f3cd30 UIApplicationMain + 159
38 My Budget 0x000000010f5c0117 main + 55
39 libdyld.dylib 0x0000000114f26d81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
经过一番检查,我发现没有标记行s.expenses = self.expenses
,就不会发生错误。此外,在对字典进行编码时,在标记的第一行aCoder.encode(self.expenses, forKey: "expenses")
中会发生错误。即使使用完整的数组对第一个原始编码进行编码也不会引起任何问题,但是第二个编码会导致错误。