问题描述
我们有一个自定义对象设置,如下所示:
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)
}
}
我们正在尝试将其转换为数据类型,以便可以将其保存为用户默认值,如下所示:
guard let bestBallParkToSave = theBestBallPark // this is of type BallPark,after fetching data
其他{return}
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(我相信我的结构及其中的所有内容都符合)之外,实际上并没有一个明确的答案。如果您有任何建议,请告诉我。
解决方法
那里的问题。是您将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 decode<T: Decodable>(_ type: T.Type,forKey defaultName: String) throws -> T {
try JSONDecoder().decode(T.self,from: data(forKey: defaultName) ?? .init())
}
func encode<T: Encodable>(_ value: T,forKey defaultName: String) throws {
try set(JSONEncoder().encode(value),forKey: defaultName)
}
}
用法:
let bestBallParkToSave = BallPark(id: "1",facilityStatus: "a status")
do {
try UserDefaults.standard.encode(bestBallParkToSave,forKey: "favoriteBallPark")
let loadedBallPark = try UserDefaults.standard.decode(BallPark.self,forKey: "favoriteBallPark")
print(loadedBallPark) // BallPark(id: "1",facilityStatus: Optional("a status"))
} catch {
print(error)
}