Swift 4:将自定义对象(带有嵌套的自定义对象)数组保存并检索到UserDefaults

时间:2018-11-28 21:05:06

标签: ios swift nsuserdefaults

我正在尝试将一组自定义对象保存到UserDefaults。我相信我现在应该正确保存,但是我继续收到“无法识别的选择器”错误。我认为这可能是因为我的自定义对象的两个部分是其他自定义对象的数组。我在这里做什么错了?

对象:

class SaleObject: NSObject, NSCoding {

//MARK: Properties

var ranges: [RangeObject]
var timberSaleName: String
var lbOperatorName: String
var lbOperatorID: String
var timberSaleID: Int
var ID: Int
var contracts: [ContractObject]

//MARK: Initialization
init(ranges: [RangeObject], timberSaleName: String, lbOperatorName: String, lbOperatorID: String, timberSaleID: Int, ID: Int ,contracts: [ContractObject]) {

    //Initialize stored properties
    self.ranges = ranges
    self.timberSaleName = timberSaleName
    self.lbOperatorName = lbOperatorName
    self.lbOperatorID = lbOperatorID
    self.timberSaleID = timberSaleID
    self.ID = ID
    self.contracts = contracts

}

required init?(coder aDecoder: NSCoder) {
    self.ranges = (aDecoder.decodeObject(forKey: "ranges") as? [RangeObject])!
    self.timberSaleName = (aDecoder.decodeObject(forKey: "timber_sale_name") as? String)!
    self.lbOperatorName = (aDecoder.decodeObject(forKey: "lb_operator_name") as? String)!
    self.lbOperatorID = (aDecoder.decodeObject(forKey: "lb_operator_id") as? String)!
    self.timberSaleID = (aDecoder.decodeObject(forKey: "timber_sale_id") as? Int)!
    self.ID = (aDecoder.decodeObject(forKey: "id") as? Int)!
    self.contracts = (aDecoder.decodeObject(forKey: "contracts") as? [ContractObject])!
}

func encode(with aCoder: NSCoder) {
    aCoder.encode(self.ranges, forKey: "ranges")
    aCoder.encode(self.timberSaleName, forKey: "timber_sale_name")
    aCoder.encode(self.lbOperatorName, forKey: "lb_operator_name")
    aCoder.encode(self.lbOperatorID, forKey: "lb_operator_id")
    aCoder.encode(self.timberSaleID, forKey: "timber_sale_id")
    aCoder.encode(self.ID, forKey: "id")
    aCoder.encode(self.contracts, forKey: "contracts")
}

}

保存尝试:

let userDefaults = UserDefaults.standard
        let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: self.saleArray)
        userDefaults.set(encodedData, forKey: "sales")

错误:

2018-11-28 14:28:30.024768-0600 Load BOSS[14991:282335] 
libMobileGestalt MobileGestalt.c:890: MGIsDeviceOneOfType is not 
supported on this platform.
2018-11-28 14:28:30.362954-0600 Load BOSS[14991:282335] [MC] System 
group container for systemgroup.com.apple.configurationprofiles path 
is /Users/beauburchfield/Library/Developer/
CoreSimulator/Devices/4ED03814-DD8C-43F3-ABA7- 
B5D0751161A0/data/Containers/Shared/SystemGroup/
systemgroup.com.apple.configurationprofiles
2018-11-28 14:28:30.364591-0600 Load BOSS[14991:282335] [MC] Reading 
from private effective user settings.
2018-11-28 14:28:31.034136-0600 Load BOSS[14991:282394] - 
[Load_BOSS.RangeObject encodeWithCoder:]: unrecognized selector sent 
 to 
instance 0x600001bcc680
2018-11-28 14:28:31.037429-0600 Load BOSS[14991:282394] *** 
Terminating app due to uncaught exception 
'NSInvalidArgumentException', reason: '-[Load_BOSS.RangeObject 
encodeWithCoder:]: unrecognized selector sent to instance 
0x600001bcc680'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010cbc51bb _ . 
_exceptionPreprocess + 331
1   libobjc.A.dylib                     0x000000010b73b735 
objc_exception_throw + 48
2   CoreFoundation                      0x000000010cbe3f44 - 
[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3   CoreFoundation                      0x000000010cbc9ed6 ___forwarding___ + 1446
4   CoreFoundation                      0x000000010cbcbda8 _CF_forwarding_prep_0 + 120
5   Foundation                          0x000000010b182175 _encodeObject + 1230
6   Foundation                          0x000000010b182aee -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 439
7   Foundation                          0x000000010b182175 _encodeObject + 1230
8   Load BOSS                           0x000000010add0e2f $S9Load_BOSS10SaleObjectC6encode4withySo7NSCoderC_tF + 207
9   Load BOSS                           0x000000010add128c $S9Load_BOSS10SaleObjectC6encode4withySo7NSCoderC_tFTo + 60
10  Foundation                          0x000000010b182175 _encodeObject + 1230
11  Foundation                          0x000000010b182aee -[NSKeyedArchiver _encodeArrayOfObjects:forKey:] + 439
12  Foundation                          0x000000010b182175 _encodeObject + 1230
13  Foundation                          0x000000010b18122e +[NSKeyedArchiver archivedDataWithRootObject:] + 156
14  Load BOSS                           0x000000010adbf15a $S9Load_BOSS18MainViewControllerC14getJsonFromUrlyyFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_ + 15706
15  Load BOSS                           0x000000010adbf43d $S9Load_BOSS18MainViewControllerC14getJsonFromUrlyyFy10Foundation4DataVSg_So13NSURLResponseCSgs5Error_pSgtcfU_TA + 13
16  Load BOSS                           0x000000010adbf590 $S10Foundation4DataVSgSo13NSURLResponseCSgs5Error_pSgIegggg_So6NSDataCSgAGSo7NSErrorCSgIeyByyy_TR + 336
17  CFNetwork                           0x000000010e0d9940 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
18  CFNetwork                           0x000000010e0efb0c __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 172
19  Foundation                          0x000000010b1a8f9e __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
20  Foundation                          0x000000010b1a8ea5 -[NSBlockOperation main] + 68
21  Foundation                          0x000000010b1a5c14 -[__NSOperationInternal _start:] + 689
22  Foundation                          0x000000010b1abc4b __NSOQSchedule_f + 227
23  libdispatch.dylib                   0x000000010f0ae595 _dispatch_call_block_and_release + 12
24  libdispatch.dylib                   0x000000010f0af602 _dispatch_client_callout + 8
25  libdispatch.dylib                   0x000000010f0b254d _dispatch_continuation_pop + 565
26  libdispatch.dylib                   0x000000010f0b1927 _dispatch_async_redirect_invoke + 859
27  libdispatch.dylib                   0x000000010f0c000a _dispatch_root_queue_drain + 351
28  libdispatch.dylib                   0x000000010f0c09af _dispatch_worker_thread2 + 130
29  libsystem_pthread.dylib             0x000000010f49e70e _pthread_wqthread + 619
30  libsystem_pthread.dylib             0x000000010f49e435 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

3 个答案:

答案 0 :(得分:1)

还必须为您的两个自定义对象实现NSCoding。其他一切都很好。

不过我想提一件事。

(aDecoder.decodeObject(forKey: "timber_sale_name") as? String)!

可以写为

aDecoder.decodeObject(forKey: "timber_sale_name") as! String

基本上含义相同,但更易于阅读。

答案 1 :(得分:1)

这里的崩溃

  

[Load_BOSS.RangeObject encodeWithCoder:]:无法识别的选择器已发送

给出了使根类符合的原因

class SaleObject: NSObject, NSCoding {

并不意味着您可以使用自定义对象(在您的情况下为RangeObject)而不必使其也像

class RangeObject : NSObject, NSCoding {

强烈建议使用Codable

class SaleObject: Codable { 

    let ranges: [RangeObject]
    let timberSaleName: String
    let lbOperatorName: String
    let lbOperatorID: String
    let timberSaleID: Int
    let ID: Int
    let contracts: [ContractObject]
}

class RangeObject : Codable { 
  // add it's properties 
}

使用方法:

let data = try? JSONEncoder().encode(obj) // obj may be single SaleObject or array

let obj = try? JSONDecoder().decode(SaleObject.self,from:data) // for data being array make it [SaleObject].self

答案 2 :(得分:1)

继续为其他两个自定义对象实现NSCoding。另外,将您的自定义对象的所有Integer上的decodeObject更改为decodeInteger,并从它们中删除“ as!Int”。然后,执行以下操作:

let userDefaults = UserDefaults.standard
let encodedData = NSKeyedArchiver.archivedData(withRootObject: self.saleArray)
userDefaults.set(encodedData, forKey: "sales")

要检索数据,请执行以下操作:

let newArray = NSKeyedUnarchiver.unarchiveObject(with: data as! Data) as! [SaleObject]

在工作之后,返回并研究Codable。享受吧!