In Swift, we all deal with JSON, plists, and various forms of [String: AnyObject]
. Marshal
believes you don't need a Ph.D. in Monads or large, complex frameworks to deal with these in an expressive and type safe way. Marshal
is a simple, lightweight framework for safely extracting values from [String: AnyObject]
.
Extracting values from [String: AnyObject]
(a.k.a. Marshal.Object
) is as easy as:
let name: String = try json.valueForKey("name")
Or, if you're into fancy high-brow operators:
let name: String = try json <| "name"
Marshal
even handles pulling values out of nested objects.
let name: String = try json.valueForKey("user.name")
Don't care about errors? Use try?
to give yourself an optional value. Otherwise, wrap it up into a do-catch
and get all the juicy details.
Often we want to take some Marshal.Object
and turn it into one of our models (like intializing a model from a JSON object). For this, Marshal
offers the ObjectConvertible
protocol.
struct User: ObjectConvertible {
var id: String
var name: String
var email: String
init(object: Object) throws {
id = try object.valueForKey("id")
name = try object.valueForKey("name")
email = try object.valueForKey("email")
}
}
Et voila! By supplying a simple initializer you can now pull your models directly out of [String: AnyObject]
.
let users: [User] = json.valueForKey("users")
Out of the box, Marshal
supports extracting native Swift types like String
, Int
, etc., as well as anything conforming to ObjectConvertible
, and arrays of the aforementioned types.
However, addding your own extractable type is as easy as extending your type with Marshal.ValueType
.
extension NSDate : ValueType {
public static func value(object: Any) throws -> NSDate {
guard let dateString = object as? String else {
throw Error.TypeMismatch(expected: String.self, actual: object.dynamicType)
}
// assuming you have a NSDate.fromISO8601String implemented...
guard let date = NSDate.fromISO8601String(dateString) else {
throw Error.TypeMismatch(expected: "ISO8601 date string", actual: dateString)
}
return date
}
}
Now you can do this!
let birthDate: NSDate = json.valueForKey("user.dob")
One of the most common occurences of [String: AnyObject]
are JSON objects. To this end, Marshal
supplies a JSONObject
typelias for Marshal.Object
, and several helper functions.
Marshal
began as a blog series on JSON parsing by Jason Larsen, but quickly evolved into a community project. Many people have contribued at one point or another to varying degrees with ideas and code:
- Bart Whiteley
- Brian Mullen
- Derrick Hathaway
- Dave DeLong
- Jason Larsen
- Mark Schultz
- Tim Shadel