Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/matthewcheok/JSONCodable
Hassle-free JSON encoding and decoding in Swift
https://github.com/matthewcheok/JSONCodable
Last synced: 2 months ago
JSON representation
Hassle-free JSON encoding and decoding in Swift
- Host: GitHub
- URL: https://github.com/matthewcheok/JSONCodable
- Owner: matthewcheok
- License: mit
- Created: 2015-06-10T22:23:33.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2020-04-22T06:51:57.000Z (over 4 years ago)
- Last Synced: 2024-10-13T14:38:06.828Z (3 months ago)
- Language: Swift
- Homepage:
- Size: 204 KB
- Stars: 602
- Watchers: 15
- Forks: 66
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-swift-cn - JSONCodable - Hassle-free JSON encoding and decoding in Swift. (Libs / Data Management)
- awesome-swift - JSONCodable - Hassle-free JSON encoding and decoding. (Libs / Data Management)
README
#JSONCodable
Hassle-free JSON encoding and decoding in Swift### Installation
- Simply add the following to your [`Cartfile`](https://github.com/Carthage/Carthage) and run `carthage update`:
```
github "matthewcheok/JSONCodable" ~> 3.0.1
```- or add the following to your [`Podfile`](http://cocoapods.org/) and run `pod install`:
```
pod 'JSONCodable', '~> 3.0.1'
```- or clone as a git submodule,
- or just copy files in the ```JSONCodable``` folder into your project.
**TLDR**
- Uses Protocol Extensions
- Error Handling
- Supports `let` properties
- Supports `enum` properties backed by compatible values**Change Log**
- Moved encoding and decoding methods to a helper class---
**JSONCodable** is made of two separate protocols `JSONEncodable` and `JSONDecodable`.
- `JSONEncodable` allows your structs and classes to generate `NSDictionary` or `[String: AnyObject]` equivalents for use with `NSJSONSerialization`.
- `JSONDecodable` allows you to generate structs from `NSDictionary` coming in from a network request for example.
##Decoding JSON
Take these two types for example:```swift
struct User {
let id: Int
let name: String
var email: String?
var company: Company?
var friends: [User] = []
}
struct Company {
let name: String
var address: String?
}
```You'd simply add conformance to `JSONDecodable` (or to `JSONCodable`):
```swift
extension User: JSONDecodable {
init(object: JSONObject) throws {
let decoder = JSONDecoder(object: object)
id = try decoder.decode("id")
name = try decoder.decode("full_name")
email = try decoder.decode("email")
company = try decoder.decode("company")
friends = try decoder.decode("friends")
}
}extension Company: JSONDecodable {
init(object: JSONObject) throws {
let decoder = JSONDecoder(object: object)
name = try decoder.decode("name")
address = try decoder.decode("address")
}
}
```**Note on Class Extensions:** After the update to Swift 2.2 adding an initializer in an extension for classes is no longer supported. The current suggested work around for this is to just add the initializer in the class definition. For structs extensions still work as that had previously in this case.
-
Then provide the implementations for `init(object: JSONObject) throws` where `JSONObject` is a typealias for `[String:AnyObject]`.
As before, you can use this to configure the mapping between keys in the Dictionary to properties in your structs and classes.```swift
let user = try User(object: JSON)
print("\(user)")
```Result:
```swift
User(
id: 24,
name: "John Appleseed",
email: Optional("[email protected]"),
company: Optional(Company(
name: "Apple",
address: Optional("1 Infinite Loop, Cupertino, CA")
)),
friends: [
User(
id: 27,
name: "Bob Jefferson",
email: nil,
company: nil,
friends: []
),
User(
id: 29,
name: "Jen Jackson",
email: nil,
company: nil,
friends: []
)
]
)
```## Decoding Nested Arrays and Dictionary
Decoding also supports retrieving values using `.` separators for dictionaries and `[index]` for arrays. See below example:
```
name = try decoder.decode("value[0].properties.name")
```## Encoding JSON
Simply add conformance to `JSONEncodable` (or to `JSONCodable`):
```swift
extension User: JSONEncodable {
func toJSON() throws -> Any {
return try JSONEncoder.create({ (encoder) -> Void in
try encoder.encode(id, key: "id")
try encoder.encode(name, key: "full_name")
try encoder.encode(email, key: "email")
try encoder.encode(company, key: "company")
try encoder.encode(friends, key: "friends")
})
}
}extension Company: JSONEncodable {}
```The default implementation of `func toJSON()` inspects the properties of your type using reflection (see `Company`.) If you need a different mapping, you can provide your own implementation (see `User`.)
Instantiate your struct, then use the `func toJSON()` method to obtain a equivalent form suitable for use with `NSJSONSerialization`:
```swift
let dict = try user.toJSON()
print("dict: \(dict)")
```Result:
```swift
[full_name: John Appleseed, id: 24, email: [email protected], company: {
address = "1 Infinite Loop, Cupertino, CA";
name = Apple;
}, friends: (
{
friends = (
);
"full_name" = "Bob Jefferson";
id = 27;
},
{
friends = (
);
"full_name" = "Jen Jackson";
id = 29;
}
)]
```
## Working with JSON Strings
The convenience initializer `init?(JSONString: String)` is provided on `JSONDecodable`. You may also use `func toJSONString() throws -> String` to obtain a string equivalent of your types.## Transforming values
To transform values, create an instance of `JSONTransformer`:
```swift
let JSONTransformerStringToNSURL = JSONTransformer(
decoding: {NSURL(string: $0)},
encoding: {$0.absoluteString})
```A `JSONTransformer` converts between 2 types, in this case, `String` and `NSURL`. It takes a closure for decoding and another for encoding, and in each case, you return an optional value of the corresponding type given an input type (you can return `nil` if a transformation is not possible).
Next, use the overloaded versions of `func encode()` and `func decode()` to supply the transformer:
```swift
struct User {
...
var website: NSURL?
}init(object: JSONObject) throws {
...
website = try JSONDictionary.decode("website", transformer: JSONTransformerStringToNSURL)
}func toJSON() throws -> AnyObject {
return try JSONEncoder.create({ (encoder) -> Void in
...
try result.encode(website, key: "website", transformer: JSONTransformerStringToNSURL)
})
}
```The following transformers are provided by default:
- `JSONTransformers.StringToNSURL`: `String <-> NSURL`
- `JSONTransformers.StringToNSDate`: `String <-> NSDate` ISO formatFeel free to suggest more!
## Extending JSONCodable (thanks to @raylillywhite)
This allows for JSONDecoder extensions that allow the type system to better aid in decoding. For example, you could do:
```swift
extension JSONDecoder {
public func decode(key: String) throws -> NSURL {
return try decode(key, transformer: JSONTransformers.StringToNSURL)
}
}
```then you only need to do:
```swift
try url = decoder.decode("url")
```instead of
```swift
try url = decoder.decode("url", JSONTransformers.StringToNSURL)
```## Example code
Refer to the included playground in the workspace for more details.
## License
`JSONCodable` is under the MIT license.