将自定义对象转换为要保存在 NSUserDefauts 中的数据 [英] Convert a custom object to Data to be saved in NSUserDefauts

查看:54
本文介绍了将自定义对象转换为要保存在 NSUserDefauts 中的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个自定义对象设置,如下所示:

We have a custom object setup like so:

struct BallPark: Codable,Equatable  {
    static func == (lhs: LeanVenue, rhs: LeanVenue) -> Bool {
        return lhs.id == rhs.id
    }
    let id: String
    let name: String?
    let location: VenueCoordinates?
    let mapEnabled: Bool?
    let facilityStatus: String?
    }

struct VenueCoordinates: Codable {
    let latitude: String?
    let longitude: String?
    
    var lat: Double? {
        guard let latitud = latitude else { return nil}
        return Double(latitud)
    }
    var lon: Double? {
        guard let longitude = longitude else { return nil}
        return Double(longitude)
    }
}

我们正在尝试将其转换为 Data 类型,以便将其保存为用户默认值,如下所示:

We are trying to convert it to type Data so it can be saved to user defaults like so:

guard let bestBallParkToSave = theBestBallPark // this is of type BallPark, after fetching data

else {return}

else {return}

 let encodedBestBallPark = NSKeyedArchiver.archivedData(withRootObject: bestBallParkToSave)
            
 UserDefaults.standard.set(encodedBestBallPark, forKey: "favoriteBallPark")

问题是在尝试转换时会导致错误:

The problem is it causes an error when trying to convert:

'NSInvalidArgumentException',原因:'-[__SwiftValueencodeWithCoder:]: 无法识别的选择器发送到实例0x6000027dca80'

'NSInvalidArgumentException', reason: '-[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x6000027dca80'

我试过使用这个堆栈溢出答案:如何转换自定义对象到 Data Swift 但除了确保它符合 Codable 之外,并没有真正明确的答案,我相信我的结构和其中的所有内容都可以.如果您有任何建议,请告诉我.

I've tried using this stack overflow answer: How to convert custom object to Data Swift but there wasn't really a clear answer except making sure it conforms to Codable which I believe my struct and everything in it does. If you have any suggestions please let me know.

推荐答案

问题在那里.是您将 Codable 与 NSCoding 混为一谈.要使用 NSKeyedArchiver 的 archivedData 方法,您需要有一个符合 NSCoding 的类.在您的情况下,您有一个符合 Codable 的结构,因此您需要使用 JSONEncoder 编码方法.注意:您的 equatable 方法声明是错误的:

The issue there. is that you are mixing up Codable with NSCoding. To use NSKeyedArchiver's archivedData method you need to have a class that conforms to NSCoding. In you case you have a structure that conforms to Codable so you need to use JSONEncoder encode method. Note: Your equatable method declaration was wrong:

struct BallPark: Codable, Equatable  {
    static func == (lhs: Self, rhs: Self) -> Bool {
        return lhs.id == rhs.id
    }
    let id: String
    let name: String?
    let location: VenueCoordinates?
    let mapEnabled: Bool?
    let facilityStatus: String?
}


struct VenueCoordinates: Codable {
    let latitude: String?
    let longitude: String?
    
    var lat: Double? {
        guard let latitud = latitude else { return nil}
        return Double(latitud)
    }
    var lon: Double? {
        guard let longitude = longitude else { return nil}
        return Double(longitude)
    }
}


let bestBallParkToSave = BallPark.init(id: "1", name: "Steve", location: .init(latitude: "20.0", longitude: "40.0"), mapEnabled: true, facilityStatus: "a status")

do {
    let encodedBestBallPark = try JSONEncoder().encode(bestBallParkToSave)
    UserDefaults.standard.set(encodedBestBallPark, forKey: "favoriteBallPark")
    if let ballParkData = UserDefaults.standard.data(forKey: "favoriteBallPark") {
        let loadedBallPark = try JSONDecoder().decode(BallPark.self, from: ballParkData)
        print(loadedBallPark)  // BallPark(id: "1", name: Optional("Steve"), location: Optional(VenueCoordinates(latitude: Optional("20.0"), longitude: Optional("40.0"))), mapEnabled: Optional(true), facilityStatus: Optional("a status"))
    }
} catch {
     print(error)
}


您还可以更轻松地扩展 UserDefaults 并创建自定义编码和解码方法:


You can also make your life easier extending UserDefaults and create customs encoding and decoding methods:

extension UserDefaults {
    func decodeObject<T: Decodable>(forKey defaultName: String, using decoder: JSONDecoder = .init()) throws -> T {
        try decoder.decode(T.self, from: data(forKey: defaultName) ?? .init())
    }
    func encode<T: Encodable>(_ value: T, forKey defaultName: String, using encoder: JSONEncoder = .init()) throws {
        try set(encoder.encode(value), forKey: defaultName)
    }
}


用法:


Usage:

let bestBallParkToSave = BallPark(id: "1", name: "Steve", location: .init(latitude: "20.0", longitude: "40.0"), mapEnabled: true, facilityStatus: "a status")
do {

    try UserDefaults.standard.encode(bestBallParkToSave, forKey: "favoriteBallPark")
    let loadedBallPark: BallPark = try UserDefaults.standard.decodeObject(forKey: "favoriteBallPark")
    print(loadedBallPark)  // BallPark(id: "1", name: Optional("Steve"), location: Optional(VenueCoordinates(latitude: Optional("20.0"), longitude: Optional("40.0"))), mapEnabled: Optional(true), facilityStatus: Optional("a status"))
    
} catch {
     print(error)
}

这篇关于将自定义对象转换为要保存在 NSUserDefauts 中的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆