如何将DateFormatter嵌入Swift结构体,避免重复配置JSONDecoder?
优化Swift 4中Twitter JSON解析:将DateFormatter嵌入结构体
这个问题问得好!你现在的代码虽然能正常解析Twitter的JSON数据,但每次都要手动配置DateFormatter和JSONDecoder的日期解码策略,确实有点冗余。咱们可以把日期解析的逻辑直接封装到Tweet结构体内部,这样之后解析的时候就不用再重复做这些配置了。下面给你两种优雅的实现方式:
方式一:自定义解码逻辑(推荐,封装性更强)
让Tweet结构体实现自定义的解码初始化方法,把DateFormatter作为静态常量放在结构体内部,这样不仅避免了重复创建格式化器的开销,还把日期解析的细节完全封装起来,外部代码不用关心任何实现逻辑。
struct Tweet: Codable { let id: String let createdAt: Date let text: String enum CodingKeys: String, CodingKey { case id = "id_str" case createdAt = "created_at" case text } // 静态常量,只初始化一次,避免重复创建的性能损耗 private static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "eee MMM dd HH:mm:ss ZZZZ yyyy" // 必须设置英文locale,避免非英文环境下解析失败(Twitter返回的是英文格式日期) formatter.locale = Locale(identifier: "en_US_POSIX") return formatter }() // 自定义解码初始化方法 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 解析普通字段 id = try container.decode(String.self, forKey: .id) text = try container.decode(String.self, forKey: .text) // 手动解析日期字符串 let dateString = try container.decode(String.self, forKey: .createdAt) guard let date = Tweet.dateFormatter.date(from: dateString) else { throw DecodingError.dataCorruptedError( forKey: .createdAt, in: container, debugDescription: "无法解析日期字符串:\(dateString)" ) } createdAt = date } }
使用的时候就非常简洁了,不需要再配置解码器的日期策略:
let decoder = JSONDecoder() let tweets = try decoder.decode([Tweet].self, from: data!)
方式二:静态配置好的解码器
如果你不想自定义解码方法,也可以把配置完整的JSONDecoder做成Tweet的静态属性,每次解析直接调用这个静态解码器即可:
struct Tweet: Codable { let id: String let createdAt: Date let text: String enum CodingKeys: String, CodingKey { case id = "id_str" case createdAt = "created_at" case text } // 静态属性,每次访问都会返回配置好的解码器 static var configuredDecoder: JSONDecoder { let decoder = JSONDecoder() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "eee MMM dd HH:mm:ss ZZZZ yyyy" dateFormatter.locale = Locale(identifier: "en_US_POSIX") decoder.dateDecodingStrategy = .formatted(dateFormatter) return decoder } }
使用时直接调用静态解码器:
let tweets = try Tweet.configuredDecoder.decode([Tweet].self, from: data!)
额外提示
不管用哪种方式,都一定要设置locale为en_US_POSIX,因为Twitter返回的日期是英文格式(比如Wed Oct 11 00:15:51 +0000 2023),如果在非英文系统环境下不指定locale,DateFormatter可能无法正确解析日期字符串。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

