sajson icon indicating copy to clipboard operation
sajson copied to clipboard

How to use Swift version?

Open own2pwn opened this issue 7 years ago • 10 comments

Hey there! I think switching enum with guard case . for every object in json isn't the best way, am I right? Could you show me real world (production) examples of using this lib?

own2pwn avatar Sep 25 '17 11:09 own2pwn

Hi! Unfortunately I don't have access to any public code that uses the library, but maybe @aeidelson could sanitize and share some.

guard case sounds fine to me though - do you have a specific objection? How else would you handle the case that the value is something you didn't expect?

If you're asking about overall structure, usually you write a series of functions from a JSON value to an Optional<SomeStruct> and compose them appropriately to decode the entire document.

Does that help?

chadaustin avatar Sep 25 '17 20:09 chadaustin

Yea, so as a convenience we (privately) declared a number of helper getters to read fields of various expected types. For example, String is declared as:

extension sajson_swift.ValueReader {
    public var stringValue: String {
        if case .string(let v) = self {
            return v
        }
        return ""
    }

    public var string: String? {
        if case .string(let v) = self {
            return v
        }
        return nil
    }
}
...
let s = someValue.string

We haven't merged these back because many of them aren't super well thought out and are pretty specific to our situation (keeping backwards compatibility with the library we moved from). But I think it would be totally reasonable to extend similar getters in SaJSON as a convenience.

aeidelson avatar Sep 26 '17 17:09 aeidelson

I'm happy to take that on if you want @chadaustin? And we could probably add some better documentation around how to use the Swift wrapper

aeidelson avatar Sep 26 '17 18:09 aeidelson

@aeidelson If you'd like, feel free! @own2pwn do you have any input into how you'd prefer decoder functions be written?

chadaustin avatar Sep 26 '17 18:09 chadaustin

A while back I began on implementing a JSON Decoder that uses Swift4‘s ˋDecodableˋ protocol and internally uses Sajson. It’s not finished yet, but ultimately that’s the way to go I guess... you can check it out in my fork here: https://github.com/t089/sajson/blob/master/swift/sajsonTests/FastJSONDecoder_Tests.swift

t089 avatar Sep 26 '17 18:09 t089

Hey, I've implemented it like aeidelson have. But that leads to deal with optional values (because of Swift's dictionary subscript). E.g.

let items = json.array
for item in items {
  let item = item.object // item's type is: [String: Value]
  let id = item["id"]?.stringValue // here we deal with String?
}

Using if case all fine if we talk about optionals but not for readability, IMO.

if case .array(let items) = json {
  var it = items.makeIterator()
  while let elem = it.next() {
    if case .object(let item) = elem {
      let id = item["id"].stringValue // because of overriding sajson's subscript, we get String -- that's nice
    }
  }
}

It would be very nice if one could use it swiftyJson way: like aeidelson suggestion with computed properties but one that returns optional and one that return parsed value or something default (string and stringValue).

Maybe there is a way to use ASTNode directly w/o enums?

own2pwn avatar Sep 26 '17 18:09 own2pwn

Also, overriding sajson's subscript leads to dirty way of handling non existing keys in json: we should return malformed ASTNode or we throw preconditionFailure

own2pwn avatar Sep 26 '17 18:09 own2pwn

Thought about it a bit: I like the idea of extending to have getters something like:

extension sajson_swift.Value {
    var string: String?
    func string(withDefault: String) -> String
    // and similar for Boolean, Arrays, etc.
}

Perhaps even getters that throw?

Anyone want to submit a PR?

I don't know anything about the new Decodable protocol, so if there's consensus around @t089's fork I'd be happy to merge that too. :)

chadaustin avatar Oct 04 '17 00:10 chadaustin

It‘s not in a mergeble(?!?) state yet. I’ll raise a PR once it is. Regardless, more convenient accessors are a plus and complement the Decodable conformance nicely.

Am 04.10.2017 um 02:08 schrieb Chad Austin [email protected]:

Thought about it a bit: I like the idea of extending to have getters something like:

extension sajson_swift.Value { var string: String? func string(withDefault: String) -> String // and similar for Boolean, Arrays, etc. } Perhaps even getters that throw?

Anyone want to submit a PR?

I don't know anything about the new Decodable protocol, so if there's consensus around @t089's fork I'd be happy to merge that too. :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

t089 avatar Oct 04 '17 06:10 t089

@chadaustin wouldn't it be better to prefer optionals rather than throwing? If I recall correctly Apple recommends using throwing funcs when dealing with hardware or when we want to describe error in more detail.

I'm happy with idea of non-optional subscript that return default value if extract failed along with two getters for other types (optional getter and getter with default value)

own2pwn avatar Oct 10 '17 12:10 own2pwn