anviking / decodable Goto Github PK
View Code? Open in Web Editor NEW[Probably deprecated] Swift 2/3 JSON unmarshalling done (more) right
License: MIT License
[Probably deprecated] Swift 2/3 JSON unmarshalling done (more) right
License: MIT License
I see that parse()
throw MissingKey
when a value can't be extracted for a key. However, catchNull()
only catches TypeMismatch
which doesn't seem appropriate for:
/// Try to decode as T, or throw. Will return nil if the object at the keypath is NSNull.
public func => <T: Decodable>(lhs: AnyObject, rhs: String) throws -> T? {
return try catchNull { try parse(lhs, path: rhs, decode: T.decode) }
}
Wouldn't this actually throw MissingKey
if rhs
is missing?
First issue 🎉!!!
So, thank you for this awesome piece of code.
I'm finding that optional arrays are not behaving the way they should: expanding on your sample from the README:
struct Repository {
let name: String
let description: String
let stargazersCount: Int
let language: String?
let owner: User
let defaultBranch: Branch
let externalContributors: [User]?
var fullName: String { return "\(owner.login)/\(name)" }
}
If we add the optional array called externalContributors
and feed the decode function with a JSON such as:
let json = [
"name" : "AwesomeKit",
"description" : "This is awesome",
"stargazers_count" : 8,
"owner" : ["login":"pcifani"],
"default_branch" : ["branch_name":"master"],
]
This should be a valid JSON for the Repository
struct, but it's not, right now, it's returning a DecodingError.TypeMismatch
with "JSON Array" as the mismatched object.
Let me know if I can help in any way
Right now you can't construct a TypeMismatchError
with an optional value. Is this by design?
Hi, possible to add a new CocoaPods version that includes the new =>?
operator?
Hi, i have a issue trying to decode an array of enums like this ["admin", "merchant"]
,
i tried like this let roles = (try j => "roles")?.map { LKUserRole(rawValue: $0)! }
but this dosent work when i dont get any role, any help would be great
u can check it here
Is there any guideline to move from 0.3.4 to 0.4?
Or any advice.
I mean, what breaks backwards compatibility?
Thanks a lot.
Hi I love Decodable but recently I encounter this situation with nested JSON.
JSON
{
"cars": [
{
"name": "bmw",
"passagers": [
{
"name": "john",
"age": "23"
},
{
"name": "lucy",
"age": "23"
}
]
},
{
"name": "ford",
"passagers": [
{
"name": "błażej",
"age": "27"
},
{
"name": "marcy",
"age": "27"
}
]
}
]
}
Structs
struct Car:Decodable{
var name:String
var passagers:[Passager]
static func decode(json:AnyObject) throws -> Passager {
return try DirectionJson(
name: json => "name",
passagers: json => [Passager].decode //? error, so how?
)
}
}
struct Passager:Decodable{
var name:String
var age:Int
static func decode(json:AnyObject) throws -> Passager {
return try DirectionJson(
name: json => "name",
age: json => "age"
)
}
}
I was hoping that whole json would be decoded by single [Car].decode(json)
. But I'm not sure how I should handle [Passager]
in Car
.
I'm trying to use Decodable to create Realm objects, but I'm having issues. Then I realized all the examples were structs — does Decodable not work with classes?
Something to ponder on
I get a build failed when i try to update via carthage
carthage update --platform iOS --no-use-binaries
*** Building scheme "Decodable-iOS" in Decodable.xcodeproj
** BUILD FAILED **
The following build commands failed:
PhaseScriptExecution Run\ Script /Users/marvinnazari/Library/Developer/Xcode/DerivedData/Decodable-bcceucalbtetbifrlcjcisqcisfe/Build/Intermediates/Decodable.build/Release-iphoneos/Decodable-iOS.build/Script-8F0062441C81F26B007BCF48.sh
(1 failure)
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/cdefs.h:707:2: error: Unsupported architecture
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/machine/_types.h:34:2: error: architecture not supported
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:55:9: error: unknown type name '__int64_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:56:9: error: unknown type name '__int32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:57:9: error: unknown type name '__int32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:60:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:61:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:62:9: error: unknown type name '__uint64_t'; did you mean 'uint64_t'?
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:68:9: error: unknown type name '__darwin_natural_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:70:9: error: unknown type name '__uint16_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:71:9: error: unknown type name '__int64_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:72:9: error: unknown type name '__int32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:73:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:74:9: error: unknown type name '__int32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:75:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types.h:76:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types/_intptr_t.h:30:9: error: unknown type name '__darwin_intptr_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/_types.h:42:9: error: unknown type name '__uint32_t'
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/include/sys/_types/_size_t.h:30:9: error: unknown type name '__darwin_size_t'; did you mean '__darwin_ino_t'?
<unknown>:0: error: too many errors emitted, stopping now
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/CoreFoundation.framework/Headers/CoreFoundation.h:11:10: error: could not build module 'Darwin'
<unknown>:0: error: could not build Objective-C module 'CoreFoundation'
A shell task failed with exit code 65:
** BUILD FAILED **
The following build commands failed:
PhaseScriptExecution Run\ Script /Users/marvinnazari/Library/Developer/Xcode/DerivedData/Decodable-bcceucalbtetbifrlcjcisqcisfe/Build/Intermediates/Decodable.build/Release-iphoneos/Decodable-iOS.build/Script-8F0062441C81F26B007BCF48.sh
(1 failure)
Preferably DecodingError.Metadata
could be replaced, but DecodingContext
is generic, so we would need something like an AnyContext
.
Though AnyContext
would basically be a DecodingError.Metadata
but with more confusing name, so maybe just improve DecodingError.Metadata
and make it be initializable with a DecodingContext
How would you map an inverse relationship using decodable?
Think of the following scenario:
A <-->> B
With A
being in a to-many
relationship with B
and B
being in a to-one
relationship with A
.
When trying to decode A
(assuming an array of B
objects are contained in the payload), the decoding of B
will be triggered as well.
I can't think of a way using decodable for populating the B
's A
reference (inverse relationship).
In theory all will be needed is to pass Self
(A
) to the mapping of B
(in the decode
function is the only thing I can think of), then having B
recognise that object, maybe as root
or parent
and assign it to the A
's reference it holds.
whats the best practice for mapping nested JSON?
Currently I am creating a struct for each level - this isn't very clever as sometimes I do not care about level.
e.g. The only data I care about is before
& after
"paging": {
"cursors": {
"before": "MTQ5MDQzODAzNzkxNzQ0MQZDZD",
"after": "ODE0NDQyNDA1MzIwMDU5"
}
}
This is my current implementation
extension Paging: Decodable {
static func decode(json: AnyObject) throws -> Paging {
return try Paging(
cursors: json => "cursors"
)
}
}
extension Paging.Cursors: Decodable {
static func decode(json: AnyObject) throws -> Paging.Cursors {
return try Paging.Cursors(
before: json => "before",
after: json => "after"
)
}
}
I want something like this:
extension Paging: Decodable {
static func decode(json: AnyObject) throws -> Paging {
return try Paging(
before: json => "cursors.before",
after: json => "cursors.after"
)
}
}
Is it possible with the current implementation or can I look at introducing some key-value coding onto the project?
Hi.
First of all great work with this library, I'd tried quite a few other Swift libraries, and this is the one that worked well with the latest version of RealmSwift for me.
Right now I'm having trouble to parse JSON arrays, if I have the following
coordinates: [-90, 14.4]
How should I specify the decoder that I want to parse the latitude and longitude from the array without having the keys?
func testNestedUnexpectedNSNull() {
let dict: NSDictionary = ["id": 1, "color": ["name": NSNull()]]
do {
let apple = try Apple.decode(dict)
print(apple)
XCTFail()
} catch DecodingError.TypeMismatch(NSNull.self, _, _) {
} catch let error {
XCTFail("should not throw this exception: \(error)")
}
}
Where the color is optional, but the color's name is not
Nested keys don't work j => "a" => "b" => "c"
Workaround:
json => ["a", "b", "c"]
Have still not investigated closely (option click for these overloads fails for me) but suspect there is some kind of String
and AnyObject
overload ambiguity.
Is it possible to combine this great object mapping library with Core Data? How should swift class look like? Thanks
Hi! Nice library. We're using Argo now and going to try this one out as a possible replacement.
One problem I'm noticing though, is that there doesn't seem to be support for regular nullable functionality. You have 2 nullable (?) operators but neither do what I would expect.
The only nullable operator (for setting an optional var) one would typically need would result in 3 cases:
This project does not satisfy case 3 and instead returns nil as well instead of an error(at least according to the documentation).
In addition, there is the array '?' operator which weeds out objects that failed to decode but in general I think it should follow the same pattern as above (with no partial successes). Allowing a partial success should probably be a special case with its own operator if at all, because in general this would be the result of developer error (unless you are depending on an unstable API).
tl:dr Should this library provide a way to decode an array or custom object in a failable/throwable way which satisfies the 3 above conditions?
Just some thoughts, what do you think?
class A {
var b: B
}
class B {
weak var a: A
let urlResponse: String
}
Injecting parameters/dependencies in sub-objects of the objects being decoded is difficult, and Decodable currently does nothing to help this.
This could be seen as the underlying problem for:
NSManagedObjectContext
(I think)Depending on the solution this could also solve/affect:
=>
has been lost in Swift 3.0)Here are two potential solutions I have thought of:
DecodingContext<Parameters>
public struct DecodingContext<T> {
var path: [String]
var json: AnyObject
var rootObject: AnyObject
var parameters: T
init(json: AnyObject, path: [String] = [], rootObject: AnyObject, parameters: T) {...}
public func parse(keys: [String]) throws -> DecodingContext {...}
public func parseAndAcceptMissingKeys(keys: [String]) throws -> DecodingContext? {...}
func map<U>(closure: (T) -> U) -> DecodingContext<U> {...}
}
public protocol Decodable {
associatedtype Parameters = Void
static func decode(_ : DecodingContext<Parameters>) throws -> Self
}
let dict: NSDictionary = ["hello": "world"]
let response = "<this is an urlresponse>"
let code = 200
let a = DecodingContext(json: dict, path: [], rootObject: dict, parameters: (urlResponse: response, code: code))
let params = a.parameters.urlResponse // <this is an urlresponse>
let params = a.parameters.code // 200
let b = a.map {
(urlResponse: $0.urlResponse, code: $0.code, additionalParamter: true)
}
b.parameters.additionalParamter // true
extension A: Decodable {
static func decode(_ context: DecodingContext<Void>) {
let context =
return A(b: context => "b")
}
}
Final design would likely be more refined, for instance with more appropriate initialisers.
=>
typealias JSON = DecodingContext<NSManagedObjectContext>
if wanted.context.parameters
itself.AnyObject
which could make it more inconvenient to work with.In the above described design each object requires a context: DecodingContext<Self.Parameters>
. For dependencies that only travel one level, e.g (the child requiring a reference to the parent) this isn't a problem. But for dependencies on the bottom (grandchildren) that needs "external" dependencies, for example the url response that the json came with, every intermediate object must also have set Parameters
that include these.
However, would be very weird if it didn't work that way.
Thinking more academically it would be practical if the decode protocol could require that the parameters are a subset of the Self.Parameter
requirement.
static func decode<P: Parameters>(_ context: DecodingContext<P>) throws -> Self {}
However with current swift version P cannot be constrained to an associatedtype. Thus we need separate contexts for decoding different things:
static func decode(context: DecodingContext<NSManagedObjectContext>) throws -> Self {
let user: User = try context => "user"
let tags: [Tags] = try context => "tags"
// Remove the NSManagedObjectContext from the parameters
let context = context.map { _ }
let url = try context => url
}
But some kind of implicit conversion (with overload) could be added for DecodingContext<T>
-> DecodingContext<Void>
conversion.
I have been playing around with this idea on this branch
public static func decode(parameter: String, foo: String) -> (AnyObject) throws -> Self {
return { json in
try Self(json: json, parameter: parameter, foo: foo)
}
}
This is a method I have been (forced) to using in some places which works by not conforming to Decodable
but instead returning a custom decode
function. Parents would then be able to inject dependencies explicitly, e.g
try b = B(json: json => "b", a: self)
Dependencies that need to be provided at a top level have to cascade down the initialization-chain.
Decodable
=>
, which is cumbersome for objects with many children with dependencies.Decodable
to help by decoding complex types like [T?]?
is removed.I think I lean more and more towards alternative 1. Nonetheless, have no strong incentive to implement this now, so going to let this sit for a while in a review-period-esque way.
So any thoughts/reactions are much appreciated!
It seems like arrays should have a separate operator (perhaps '=>|', piped added to regular operator) because receiving an object when expecting an array or vice versa is a valid error case.
Consider the possibility that you are expecting an object of type 'Hat'. Your API is erroneously returning an array of hats so you get [Hat]. Decodable will unfortunately not catch this for you because it doesn't know that you don't want an array.
TimeMismatch(type: Any.Type <<---- EXPECTED OR ACTUAL?)
Hi @Anviking,
I've been reading the new changes in the code, fantastic job with the errors.
I saw this:
public protocol MetaDecodable {
typealias MetaType
var objects: MetaType {get}
static func decode(json: AnyObject, type: Decodable.Type) throws -> MetaType
}
I'm not sure if MetaDecodable
is used, could you explain the idea behind please?
Thanks
Hej
To additionally make Bool, Int and Double decodable from String values.
extension Bool {
public static func decode(j: AnyObject) throws -> Bool {
switch j {
case is Bool:
return j as! Bool
case is String:
switch j as! String {
case "true": return true
case "false": return false
default: throw DecodingError.UnexpectedValue(value: j, info: DecodingError.Info(object: j))
}
default:
let info = DecodingError.Info(object: j)
throw DecodingError.TypeMismatch(type: j.dynamicType, expectedType: self, info: info)
}
}
}
This implementation is not called when doing the usual, e.g.:
struct MyDecodableType : Decodable {
let myBool: Bool
public static func decode(j: AnyObject) throws -> MyDecodableType {
return try MyDecodableType(myBool: j => "myBool")
}
}
instead, it only works when doing this:
return try MyDecodableType(myBool: try parse(json, path: ["myBool"], decode: Bool.decode))
Using this everywhere there's a Bool, Int or Double isn't an option.
T
should resolve to Bool
inside of =>
, but T.decode
always seems to resolve to Castable's implementation...
Dynamic dispatch seems to follow some simple rules when it comes to instances (https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94#.1wkt1dbt7), but what is going on here?
It would be really great for updating objects on your REST api if you could automatically encode Decodable objects back into JSON. I may look into implementing this, but wanted to hear thoughts on this, or if you're perhaps already working on it.
Hi i get a error when i try decode a Dictionary
public struct ShowMorePosts {
public let posts: [STPost]
public let showMorePosts: [String:[STPost]]
}
extension ShowMorePosts: Decodable {
public static func decode(j: AnyObject) throws -> ShowMorePosts {
return try ShowMorePosts(
posts: j => "posts",
showMorePosts: j => "show_more_posts"
)
}
}
Note: STPost is confirming to Decodable
I get this error Cannot convert value of type 'AnyObject' to expected argument type '[String : [STPost]]'
Hi,
Sorry that this is more of a question than a bug I am sure, but trying to include tests that use any of the decode
functions fails to compile with
Undefined symbols for architecture x86_64:
"static (extension in Decodable):Swift.Array<A where A: Decodable.Decodable>.(decode (Swift.AnyObject, ignoreInvalidObjects : Swift.Bool) throws -> [A]).(default argument 1)", referenced from:
CityBikesKitTests.CityBikesTests.testNetworksAreSortedAlphabetically () -> () in CityBikesTests.o
"static (extension in Decodable):Swift.Array<A where A: Decodable.Decodable>.decode (Swift.AnyObject, ignoreInvalidObjects : Swift.Bool) throws -> [A]", referenced from:
CityBikesKitTests.CityBikesTests.testNetworksAreSortedAlphabetically () -> () in CityBikesTests.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Strangely enough if I commented out the problematic line, and run the same code in the console with a breakpoint on that test, everything works normally. Have you seen this before? Any suggestions?
You can see the problematic line (actually any that uses decode
will do, yet if you see the arrow at the bottom, that code works in the console
What's the right way to decode values when the key itself may be missing? For certain values, I'd like to provide a default value when the key is missing from the JSON. e.g.
let memo: String? = try j => "memo" <= nil
Could Nate Cook's solution for ternary operators in Swift be used? http://natecook.com/blog/2014/10/ternary-operators-in-swift/
Would love to see this working with swift 3 to test soon :) Happy to contribute in any way that's useful!
Right now it can be difficult to understand from where the parsing error originates. The following works on the functions
-branch, but not sure about the vastly different and somewhat weird implementation.
let dict: NSDictionary = ["object": ["repo": ["owner": ["id" : 1, "login": "anviking"]]]]
do {
let usernames: String = try dict => "object" => "repo" => "owner" => "lllloogon"
} catch let error {
print(error)
}
===============================
MissingKey at object.repo.owner: lllloogon in {
id = 1;
login = anviking;
}
Other approaches could be making allowing => ["repo", "owner", "login"]
and possibly add func =>(lhs: String, rhs: String) -> [String]
This library is great, I've been using it with some of my structs and it I dig it. How can I use this to return "JSON Objects", i.e. a raw JSON object?
Hi,
What is the best practice for missing keys? I find it strange (I'm sure I'm wrong here) that the decoding process fails when it founds a missing key and this property is marked as Optional. Is it normal for API responses to not include all the information in their entities for every single call?
I am trying to consume an "index" action that returns some data about the model and a "show" action that shows all the data, but since the "index" is a trimmed down version of the "show" it always fails.
Hi, this is a question on how to work with Decodable.
I'm talking to an API that gives me a dictionary of the type Dictionary<String,City>
where City
is another decodable type. This is the naïve way I tried to start with, but I'm unsure how else to go about this.
struct Metadata: Decodable {
...
let cities: [String: City]
static func decode(json: AnyObject) throws -> Metadata {
return try Metadata(
...
cities: json => "cities"
)
}
}
TypeMismatch __NSCFDictionary, expected: Dictionary<String, City> in cities object:
Thanks for any tips! :)
Currently the podspec in the repo supports OS X, but isn't pushed to cocoapods.
Also theres been a lot of good work on master the last couple months, but no new tags, podspec updates/pushes.
I'm very much invested in the growth/up-to-dateness of Decodable, and would be happy to maintain the podspec, if added as a maintainer.
Thanks
When trying to use Decodable with classes, I get a odd Xcode error no calls to throwing functions occur within 'try' expression
. It's odd because while I can see the line that causes it, Xcode itself doesn't associate the warning with the specific line. And, I don't actually get the error as the init
function does throw.
class Model: NSObject, Decodable {
var name: String
required init(json: AnyObject) throws {
try self.name = json => "name"
}
static func decode(j: AnyObject) throws -> Self {
// Xcode does not like this line
return try self.init(json: j)
}
}
So my questions are:
Thanks so much!
Some kind of abstraction is needed I think, they're pretty messy now. DecodingError should be equatable or something.
Hey, I'm trying to allow easy decoding on things like NSURL / NSDate etc… Seems the protocol is complaining when trying to add it to a ObjC class.
Keeps asking 'expected return type to be Self' but if you do that then the return types break.
Have you done this at all?
So people that are not emotionally attached to them can use function-overloads instead. If the operators should exist they should be entirely optional. Originally planned it for v0.3
but it never happened. (You have to write twice the number of overloads). Opening this now because of a lot of really valid skepticism towards Decodable
's operators on twitter.
Here some of my thoughts;
=>?
do?So, yeah.
But I do think many people, including myself, want to keep their model-deserializing code short and implicit. So I believe in keeping the operators, just making them optional.
parse<T>(son: AnyObject, path: String...)
probably?)Note: subscripts would of course be nice, but they can't be generic or throwing.
Edit No, I have changed my mind again for the bizillionth time. I really don't know if I should do this, meaning nothing will change for now.
The more sane thing is perhaps to have the optional =>
to throw on a missing key (but accept an explicit null anywhere), and add a completely non-throwing =>?
operator
Hi There! I'm really liking your library. I'm currently attempting to decode responses I get from Alamofire's responseJSON
serializer but I'm encountering issues. Here's a print out of the JSON response. It looks as expected:
Optional({
id = 173722;
token = 9eea351ff15d43d1609145eb699412cc4297b58d173722;
user = {
"activities_total" = 12780;
avatar = "https://stagingsite.s3.amazonaws.com/avatars/[email protected]";
"avatar_lg" = "https://stagingsite.s3.amazonaws.com/avatars/173722orig.jpeg";
"competitions_on" = 1;
converter = 1;
"first_name" = "";
gender = Male;
"giveaway_points_on" = 1;
"goal_enforced" = 0;
"inception_date" = "2015-07-27 11:44:11";
"last_name" = "";
"last_visit" = "2015-10-02 11:26:04";
level = 2;
"levels_and_points" = 1;
logo = "https://stagingsite.s3.amazonaws.com/logos/saZIvy_mountain-2.jpg";
"mobilehealth_allowed" = 1;
"number_of_entries" = 22;
"pedometer_image" = "https://api.stagingsite.com/_views/images/devices/googlefit32.png";
"pedometer_last_contact" = 1441394474;
"pedometer_name" = Googlefit;
"pedometer_type" = "Google Fit";
points = 270;
"points_granted" = 0;
"points_to_grant" = 36;
"program_end" = "2017-01-31";
"program_start" = "2013-10-01";
"step_average" = 4155;
"step_goal" = 8000;
"step_goal_met" = 0;
"step_total" = 78628;
"stride_length" = 0;
"teams_on" = 1;
"this_device" = "app_name/com. appname.app-name (1; os version 9.0 (build 13a340))";
"total_privacy" = 0;
units = Miles;
url = "beta.stagingsite.com";
username = somerusername;
};
username = someusername;
})
Then I have a struct for a UserSession and a User. The issue is that sometimes I'll get an error on attributes that are not set to be a String. For example, several of these attributes should be Bool's or Ints. In some cases this works fine. For example these attributes parse correctly:
struct User {
...
var competitionsOn: Int
var giveawayPointsOn: Bool
var mobilehealthAllowed: Int
...
}
But every so often one of the attributes throws this error:
TypeMismatch NSTaggedPointerString, expected: Int in user.number_of_entries object: Optional(22)
The correct value was found (22) but it's showing up as an Optional. Are there any additional steps I should take when parsing values to describe or cast their type? I currently am just using the most basic implementation per the examples:
numberOfEntries: j => "number_of_entries",
In any case -- adjusting the attribute type to a String resolves the parsing error but that is not ideal.
I found when debugging the NSError thrown does not mention what failed -
I get this error:
Error Domain=Decodable.DecodingError Code=0 "(null)"
It is simple to reproduce,
extension Event.Place: Decodable {
static func decode(json: AnyObject) throws -> Event.Place {
return try Event.Place(
name: json => "title",
longitude: json => "location" => "longitude",
latitude: json => "location" => "latitude"
)
}
}
let json = [
"name" : "Home",
"location" : [
"longitude" : 0,
"latitude" : 0
]
]
Notice the mistake in the decode - using "title" instead of "name", it would be nice if we could yield that result into the error
Decodable reside in a base framework in our project to access path, object and rootObjec from other framework is not possible without making them public. Can you please make that change ?
public struct Info {
public init(object: AnyObject, rootObject: AnyObject? = nil, path: [String] = []) {
self.object = object
self.rootObject = rootObject
self.path = path
}
public var path: [String]
public var object: AnyObject?
public var rootObject: AnyObject?
public var formattedPath: String {
return path.joinWithSeparator(".")
}
}
Currently the =>
operators that return T?
, [T]?
, etc. will throw a .MissingKey
if the key path is missing. For JSON not having a field be available is usually the same as having it explicitly be null
. Right now the documentation suggests try?
for cases like this, but then you will swallow .TypeMismatch
errors.
I recommend that either the =>
operators that return a nil
also do so on .MissingKey
, or a new set of operators, such as =>?
, be introduced. The type already states that it's valid for it to not exist (the point of an Optional
in my mind) and .MissingKey
matches that.
It may actually be useful now that we have the RawRepresentable
extension.
Something like:
public protocol Transformable: Decodable {
typealias RawDecodableType: Decodable
static func transform(rawValue: RawDecodableType) throws -> Self?
}
Purpose: Automatically throw an useful error if transform fails. This would replace the error for the RawRepresentable
extension.
Note: Tempted to call it Transformable
but probably shouldn't
Say we have an object, which should be initialised from a JSON coming over the network and from a different JSON e.g. coming from the disk. This is currently not possible since, the decode
function has no way of knowing the "type" of the JSON it is getting.
Adding type information to the Decodable
protocol would allow for having different decode
functions to work with the same object:
public protocol Decodable {
typealias DataSourceType
static func decode(json: AnyObject, ofType type:DataSourceType.Type) throws -> Self
}
// It could look something like this...
struct TheObject {
let info:String
}
struct ServerJSON {}
extension TheObject : Decodable {
typealias DataSourceType = ServerJSON
static func decode(json: AnyObject, ofType type:DataSourceType.Type) throws -> TheObject
{
return TheObject(info: "fromServer")
}
}
struct DiskJSON {}
extension TheObject {
static func decode(json: AnyObject, ofType type:DiskJSON.Type) throws -> TheObject
{
return TheObject(info: "fromDisk")
}
}
let o = try! TheObject.decode(["Some":"Thing"], ofType: ServerJSON.self)
o.info // -> "fromServer"
let p = try! TheObject.decode(["Some":"Thing"], ofType: DiskJSON.self)
p.info // -> "fromDisk"
It seems Swift PM only handles numbers in versions, hence the current version tagging scheme (prepending with v as github suggests) doesn't allow to use this library as a package dependency (it only pick ups the old 0.3.1 version). Changing the tag names to omit the v fixes this.
I can’t figure out for the life of me why the following does not work:
struct Foo: Decodable {
let bar: String?
static func decode(object: AnyObject) throws -> Foo {
return try Foo(bar: object =>? "bar")
}
}
When parsing the following JSON:
{
"bar": null
}
I would expect decode
to not throw, and instead return Foo(bar: nil)
. What happens instead, is MissingKeyError(key: "bar")
.
Decodable.swift:53:27: Curried function declaration syntax will be removed in a future version of Swift; use a single parameter list
DecidingError.Info is really strange, perhaps there is a better way
public func decodeArrayLazily<T>(elementDecodeClosure: AnyObject throws -> T) -> (json: AnyObject) throws -> [T] {
return { json in
return try (NSArray.decode(json) as [AnyObject]).lazy.map { try elementDecodeClosure($0) }
}
}
Perhaps this could be useful. I should investigate performance sometime.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.