У меня есть пользовательский объект 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")
.Несмотря на то, что первоначальное кодирование для первого с помощью неповрежденного массива не вызывает никаких проблем, второе кодирование вызывает ошибку.