我创建了一个属性包装器,如下所示:

@propertyWrapper
public struct DefaultTodayDate: Codable {
    public var wrappedValue: Date

    private let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "y-MM-dd'T'HH:mm:ss"

        return formatter
    }()

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        var stringDate = ""
        do {
            stringDate = try container.decode(String.self)
            self.wrappedValue = self.dateFormatter.date(from: stringDate) ?? Date()
        } catch {
            self.wrappedValue = Date()
        }
    }

    public func encode(to encoder: Encoder) throws {
        try wrappedValue.encode(to: encoder)
    }
}

还有一个这样的模型:

struct MyModel: Codable {
    @DefaultTodayDate var date: Date
}

因此,如果我想要解析这个json文件,一切都很正常:

let json = #"{ "date": "2022-10-10T09:09:09" }"#.data(using: .utf8)!
let result = try! JSONDecoder().decode(MyModel.self, from: json)

print(result) // result.date is: 2022-10-10 09:09:09 +0000
-----

let json = #"{ "date": "" }"#.data(using: .utf8)!
let result = try! JSONDecoder().decode(MyModel.self, from: json)

print(result) // result.date is: Date()
-----

let json = #"{ "date": null }"#.data(using: .utf8)!
let result = try! JSONDecoder().decode(MyModel.self, from: json)

print(result) // result.date is: Date()

但是我也想解析一个没有date个属性的JSON.致命错误:

let json = #"{ "book": "test" }"#.data(using: .utf8)!
let result = try! JSONDecoder().decode(MyModel.self, from: json)

// Fatal error: 'try!' expression unexpectedly raised an error: Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "date", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"date\", intValue: nil) (\"date\").", underlyingError: nil))

print(result) // i want to result.date be Date() 

推荐答案

您可以通过向KeyedDecodingContainerProtocol(或KeyedDecodingContainer)添加一个新的decode(_:forKey:)方法来实现这一点,该方法将在默认一致性Decodable的情况下自动使用.

此方法必须将属性包装的.Type作为其第一个参数,并返回属性包装的一个实例.

在您的示例中,这样的扩展如下所示:

extension KeyedDecodingContainerProtocol { // KeyedDecodingContainer works too
    public func decode(_ type: DefaultTodayDate.Type, forKey key: Key) throws -> DefaultTodayDate {
        return try decodeIfPresent(type, forKey: key) ?? DefaultTodayDate(wrappedValue: Date())
    }
}

然后,只需将此初始值设定项添加到您的DefaultTodayDate类型:

public init(wrappedValue: Date) {
    self.wrappedValue = wrappedValue
}

您失败的示例现在可以正常运行:

let json = #"{ "book": "test" }"#.data(using: .utf8)!
let result = try! JSONDecoder().decode(MyModel.self, from: json)
print(result.date) // 2022-09-08 08:16:33 +0000
print(Date())      // 2022-09-08 08:16:33 +0000

Ios相关问答推荐

使用CGAffineTransform旋转视图只起作用一次吗?

RxSwift:如何使用另外两个可观测对象(其中一个依赖于另一个)创建可观测对象?

SWIFT AVFoundation不能在查看更新的同时发布更新

执行devicectl:ProcessException时出错:进程异常退出:错误:命令超时超过5.0秒

从包含 5 个以上项目的自定义选项卡栏的导航视图中删除更多按钮

使用异步重载实现Swift协议一致性

Swift/iOS:泛型错误:协议需要嵌套类型V;你想添加它吗?

如何在 SwiftUI 中创建显示当前电池电量的电池徽章

AVPlayer 退出全屏

访问未定义的 stage_in 金属着色器参数

如何在导航栏右侧添加多个 UIBarButtonItem?

从 NSData 或 UIImage 中查找图像类型

有没有办法在 xib 文件中的视图和顶部布局指南之间添加约束?

比较没有时间分量的 NSDates

iOS 7 及更高版本: for each 视图控制器设置状态栏样式

在 UITableViewController 中使用 UISearchDisplayController 时断言失败

Swift:如何在设备旋转后刷新 UICollectionView 布局

从 Swift 转换为 Objective-c 的工具

如何为 NSDate 添加一个月?

如何检测快速touch 或单击的tableView单元格