Восстановление значения UserDefaults для ключа приводит к ошибке в Swift 4 - PullRequest
0 голосов
/ 25 июня 2018

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

...