https://github.com/tattn/morecodable
MoreCodable expands the possibilities of `Codable`.
https://github.com/tattn/morecodable
codable ios linux macos swift
Last synced: 10 months ago
JSON representation
MoreCodable expands the possibilities of `Codable`.
- Host: GitHub
- URL: https://github.com/tattn/morecodable
- Owner: tattn
- License: mit
- Created: 2018-02-11T12:22:08.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2023-12-01T18:25:55.000Z (about 2 years ago)
- Last Synced: 2025-04-02T23:18:04.900Z (10 months ago)
- Topics: codable, ios, linux, macos, swift
- Language: Swift
- Homepage:
- Size: 104 KB
- Stars: 380
- Watchers: 3
- Forks: 23
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
MoreCodable
MoreCodable expands the possibilities of "Codable".
# Installation
## Carthage
```ruby
github "tattn/MoreCodable"
```
## CocoaPods
```ruby
pod 'MoreCodable'
```
# Feature
## DictionaryEncoder / DictionaryDecoder
```swift
struct User: Codable {
let id: Int
let name: String
}
let encoder = DictionaryEncoder()
let user = User(id: 123, name: "tattn")
let dictionary: [String: Any] = try! encoder.encode(user) // => {"id": 123, "name": "tattn"}
```
```swift
let decoder = DictionaryDecoder()
let user = try decoder.decode(User.self, from: dictionary)
```
## URLQueryItemsEncoder / URLQueryItemsDecoder
```swift
struct Parameter: Codable {
let query: String
let offset: Int
let limit: Int
}
let parameter = Parameter(query: "ねこ", offset: 10, limit: 20)
let encoder = URLQueryItemsEncoder()
let params: [URLQueryItem] = try! encoder.encode(parameter)
var components = URLComponents(string: "https://example.com")
components?.queryItems = params
components?.url // https://example.com?query=%E3%81%AD%E3%81%93&offset=10&limit=20
```
```swift
let decoder = URLQueryItemsDecoder()
let parameter = try decoder.decode(Parameter.self, from: params)
```
## ObjectMerger
```swift
struct APIResponse: Encodable {
let id: Int
let title: String
let foo: String
}
struct APIResponse2: Encodable {
let tags: [String]
}
struct Model: Decodable {
let id: Int
let title: String
let tags: [String]
}
let response = APIResponse(id: 0, title: "Awesome article", foo: "bar")
let response2 = APIResponse2(tags: ["swift", "ios", "macos"])
let model = try ObjectMerger().merge(Model.self, response, response2)
// success
XCTAssertEqual(model.id, response.id)
XCTAssertEqual(model.title, response.title)
XCTAssertEqual(model.tags, response2.tags)
```
## RuleBasedCodingKey
```swift
struct User: Codable {
let userId: String
let name: String
enum CodingKeys: String, RuleBasedCodingKey {
case userId
case name
func codingKeyRule(key: String) -> String {
return key.uppercased() // custom rule
}
}
}
let json = """
{"USERID": "abc", "NAME": "tattn"}
""".data(using: .utf8)!
let user = try! JSONDecoder().decode(User.self, from: json) // => User(userId: "abc", name: "tattn")
```
### SnakeCaseCodingKey
```swift
struct User: Codable {
let userId: String
let name: String
enum CodingKeys: String, SnakeCaseCodingKey {
case userId
case name
}
}
let json = """
{"user_id": "abc", "name": "tattn"}
""".data(using: .utf8)!
let user = try! JSONDecoder().decode(User.self, from: json) // ok
```
### UpperCamelCaseCodingKey
```swift
struct User: Codable {
let userId: String
let name: String
enum CodingKeys: String, UpperCamelCaseCodingKey {
case userId
case name
}
}
let json = """
{"UserId": "abc", "Name": "tattn"}
""".data(using: .utf8)!
let user = try! JSONDecoder().decode(User.self, from: json) // ok
```
## Failable
```swift
let json = """
[
{"name": "Taro", "age": 20},
{"name": "Hanako"}
]
""".data(using: .utf8)! // Hanako has no "age"
struct User: Codable {
let name: String
let age: Int
}
let users = try! JSONDecoder().decode([Failable].self,
from: json)
// success
XCTAssertEqual(users[0].value?.name, "Taro")
XCTAssertEqual(users[0].value?.age, 20)
XCTAssertNil(users[1].value)
```
## StringTo
```swift
let json = """
{
"int": "100",
"articleId": "abc"
}
""".data(using: .utf8)!
struct Root: Codable {
let int: StringTo
let articleId: StringTo
struct ArticleId: LosslessStringConvertible, Codable {
var description: String
init?(_ description: String) {
self.description = description
}
}
}
let root = try! JSONDecoder().decode(Root.self, from: json)
// success
XCTAssertEqual(root.int.value, 100)
XCTAssertEqual(root.articleId.value.description, "abc")
```
## MultiDateFormat
```swift
let json = """
{
"date": "2019.05.27",
"dateTime": "2019-05-27T17:26:59+0000",
"timestamp": 1558978068,
"timestampMilliseconds": 1558978141863,
"custom": "1558978068"
}
""".data(using: .utf8)!
struct Document: Codable {
var date: Date
var dateTime: Date
var timestamp: Date
var timestampMilliseconds: Date
var custom: Date
}
extension Document: MultiDateFormat {
static var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")
formatter.dateFormat = "yyyy.MM.dd"
return formatter
}()
static func dateFormat(for codingKey: CodingKey) -> DateFormat? {
switch codingKey {
case CodingKeys.date: return .formatted(dateFormatter)
case CodingKeys.dateTime: return .iso8601
case CodingKeys.timestamp: return .secondsSince1970
case CodingKeys.timestampMilliseconds: return .millisecondsSince1970
case CodingKeys.custom: return .custom({ (date, encoder) in
var container = encoder.singleValueContainer()
try container.encode(String(date.timeIntervalSince1970))
}, { (decoder) -> Date in
let container = try decoder.singleValueContainer()
let string = try container.decode(String.self)
let timeInterval = TimeInterval(string)!
return Date(timeIntervalSince1970: timeInterval)
})
default: return nil
}
}
}
let decoded = try! MoreJSONDecoder().decode(Document.self, from: json)
let encoded = try! MoreJSONEncoder().encode(document)
```
## DictionaryCachableEncoder
```swift
struct User: Codable, Hashable { // conform to Hashable
let id: Int
let name: String
}
let encoder = DictionaryCachableEncoder()
let user = User(id: 123, name: "tattn")
let dictionary: [String: Any] = try! encoder.encode(user) // => {"id": 123, "name": "tattn"}
try! encoder.encode(user) // use the previous encoded result for the second time
```
# ToDo
- [ ] XMLDecoder/XMLEncoder
- [ ] CSVDecoder/CSVEncoder
# Related project
**DataConvertible**
https://github.com/tattn/DataConvertible
# Contributing
1. Fork it!
2. Create your feature branch: `git checkout -b my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin my-new-feature`
5. Submit a pull request :D
## Support this project
Donating to help me continue working on this project.
[](https://paypal.me/tattn/)
# License
MoreCodable is released under the MIT license. See LICENSE for details.