Jer*_*kar 3 optional ios swift
我正在处理来自JSON的数据,我必须将它们解析成一个快速的对象.我用这个代码:
struct MyGPSCoords {
var latitude:Double
var longitude:Double
var accuracy:Int
var datetime:NSDate
init?(infobrutFromJson_:[String:String]?)
{
guard let infobrut = infobrutFromJson_ else {
// first time the user sign up to the app, php server returns "null" in Json
return nil
}
guard
let lat:Double = Double(infobrut["latitude"] ?? "nil"),
let lng = Double(infobrut["longitude"] ?? "nil"),
let acc = Int(infobrut["accuracy"] ?? "nil"),
let dtm = NSDate(timeIntervalSince1970: Double(infobrut["time"] ?? "nil"))
else {
print("warning : unable to parse data from server. Returning nil");
return nil ; // position not NIL but format not expected => = nil
}
self.latitude = lat
self.longitude = lng
self.accuracy = acc
self.datetime = dtm
}
}
Run Code Online (Sandbox Code Playgroud)
我想让"守卫"声明尽可能短.例如,我补充说?"nil"所以如果其中一个键不存在,则Double("nil")= nil并且guard语句可以处理.对于NSDate,我使用方便init进行了扩展?如果它的参数是零,则返回nil,所以我可以这样.
现在我的问题是,我可以通过直接在guard.latitude中分配保护声明中的值吗?当我尝试这个:
guard self.latitude = Double(infobrut["latitude"] ?? "nil"), ...
Run Code Online (Sandbox Code Playgroud)
它说它不能从Double投出?加倍..所以,有没有办法让这个后卫更短,并避免我分配lat,lng,acc和dtm缓冲变量?
首先,您当然应该尝试修复JSON,因为这个JSON格式不正确.字符串不是JSON中的数字.假设你无法纠正这个破坏的JSON,你想要的工具是flatMap,它转换为T ?? 到T?(这是后卫所期望的).
guard
let lat = infobrut["latitude"].flatMap(Double.init),
let lng = infobrut["longitude"].flatMap(Double.init),
let acc = infobrut["accuracy"].flatMap(Int.init),
let dtm = infobrut["time"].flatMap(TimeInterval.init).flatMap(Date.init(timeIntervalSince1970:))
else {
print("warning : unable to parse data from server. Returning nil")
return nil // position not NIL but format not expected => = nil
}
Run Code Online (Sandbox Code Playgroud)
我看到很多评论说Codable在这里不会起作用,但绝对会这样,而且它应该是你应该使用的.这是一种方式(这是关于它的错误消息有点草率,但它很简单):
struct MyGPSCoords: Decodable {
var latitude:Double
var longitude:Double
var accuracy:Int
var datetime:Date
enum CodingKeys: String, CodingKey {
case latitude, longitude, accuracy, datetime
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
guard
let lat = Double(try container.decode(String.self, forKey: .latitude)),
let lng = Double(try container.decode(String.self, forKey: .longitude)),
let acc = Int(try container.decode(String.self, forKey: .accuracy)),
let dtm = TimeInterval(try container.decode(String.self,
forKey: .datetime)).flatMap(Date.init(timeIntervalSince1970:))
else {
throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "Could not decode"))
}
self.latitude = lat
self.longitude = lng
self.accuracy = acc
self.datetime = dtm
}
}
Run Code Online (Sandbox Code Playgroud)
或者您可以通过内部有用的功能获得真正的幻想,并通过强大的功能摆脱所有临时变量和选项throws.
struct MyGPSCoords: Decodable {
var latitude:Double
var longitude:Double
var accuracy:Int
var datetime:Date
enum CodingKeys: String, CodingKey {
case latitude, longitude, accuracy, datetime
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
func decodeBrokenJSON<T>(_ type: T.Type,
forKey key: CodingKeys) throws -> T
where T: Decodable & LosslessStringConvertible {
return try T.init(container.decode(String.self, forKey: key)) ?? {
throw DecodingError.dataCorruptedError(forKey: key,
in: container,
debugDescription: "Could not decode \(key)")
}()
}
self.latitude = try decodeBrokenJSON(Double.self, forKey: .latitude)
self.longitude = try decodeBrokenJSON(Double.self, forKey: .longitude)
self.accuracy = try decodeBrokenJSON(Int.self, forKey: .accuracy)
self.datetime = Date(timeIntervalSince1970: try decodeBrokenJSON(TimeInterval.self, forKey: .datetime))
}
}
Run Code Online (Sandbox Code Playgroud)
(国际海事组织,这是一个很好的例子,说明它是如何throws真正发光的,并且应该比通常使用得多.)
| 归档时间: |
|
| 查看次数: |
285 次 |
| 最近记录: |