重新保存键的UserDefaults值会在swift 4中产生错误

时间:2018-06-24 22:22:11

标签: swift nsuserdefaults encode

我有一个自定义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")中会发生错误。即使使用完整的数组对第一个原始编码进行编码也不会引起任何问题,但是第二个编码会导致错误。

0 个答案:

没有答案