将自定义对象转换为要保存在 NSUserDefauts 中的数据
Posted
技术标签:
【中文标题】将自定义对象转换为要保存在 NSUserDefauts 中的数据【英文标题】:Convert a custom object to Data to be saved in NSUserDefauts 【发布时间】:2020-11-03 21:26:23 【问题描述】:我们有一个像这样的自定义对象设置:
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 类型,以便可以将其保存为用户默认值,如下所示:
guard let bestBallParkToSave = theBestBallPark // this is of type BallPark, after fetching data
否则返回
let encodedBestBallPark = NSKeyedArchiver.archivedData(withRootObject: bestBallParkToSave)
UserDefaults.standard.set(encodedBestBallPark, forKey: "favoriteBallPark")
问题是它在尝试转换时会导致错误:
'NSInvalidArgumentException',原因:'-[__SwiftValue encodeWithCoder:]: 无法识别的选择器发送到实例 0x6000027dca80'
我尝试过使用这个堆栈溢出答案:How to convert custom object to Data Swift,但除了确保它符合我相信我的结构和其中的所有内容的 Codable 之外,并没有真正明确的答案。如果您有任何建议,请告诉我。
【问题讨论】:
【参考方案1】:那里的问题。是您将 Codable 与 NSCoding 混为一谈。要使用 NSKeyedArchiver 的 archivedData 方法,您需要有一个符合 NSCoding 的类。在您的情况下,您有一个符合 Codable 的结构,因此您需要使用 JSONEncoder 编码方法。注意:您的等价方法声明是错误的:
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 并创建自定义编码和解码方法:
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)
用法:
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)
【讨论】:
如果使用了JSONEncoder方法,还能保存到NSUserDefaults吗? 好的,这更有意义。我去试试,谢谢!以上是关于将自定义对象转换为要保存在 NSUserDefauts 中的数据的主要内容,如果未能解决你的问题,请参考以下文章
Typescript/Angular 12:将自定义对象转换为参数对象