Git Product home page Git Product logo

gloss's Introduction

Gloss

๐Ÿšจ Deprecation Notice ๐Ÿšจ

Gloss has been deprecated in favor of Swift's Codable framework.

The existing Gloss source is not going away, however updates will only be made to support migration to Codable. Read the MIGRATION GUIDE now to get started.

If you do not yet have any Gloss models in your project yet are considering it for JSON parsing, turn around now! Select Swift's Codable framework instead.

I understand, I'm Using Gloss Anyway

Swift version CocoaPods Carthage compatible SPM CocoaPods Build Status

See the former README.md on instructions for using Gloss pre-Codable migration.

Credits

Gloss was created by Harlan Kellaway

Thank you to all contributors and the Swift community for 5 years of Gloss! ๐Ÿ’–

License License

See the LICENSE file for more info.

Codable Migration Quick Reference

The following is a reference for what your Gloss models and call-sites should look like after preparing to migrate to Codable.

See the MIGRATION GUIDE for more detail.

Version

Use version 3.2.0 or higher to take advantage of migration helpers.

Deserialization

Given a Gloss model that conforms to JSONDecodable, add conformance to Decodable. A model that looks like this:

import Gloss

struct MyModel: JSONDecodable {
    let id: Int?
    
    init?(json: JSON) {
        self.id = "id" <~~ json
    }
}

adds

extension MyModel: Decodable {

    init(from decoder: Swift.Decoder) throws {
        // Proper Decodable definition or throw GlossError.decodableMigrationUnimplemented
        // Remove this method if Codable can synthesize decoding for you
    }

}

Initializing a Model from JSON

Where initializing that model currently looks like:

let myModel = MyModel(json: someJSON)

it becomes:

let myModel: MyModel = .from(decodableJSON: someJSON)

Serialization

Given a Gloss model that conforms to JSONEncodable, add conformance to Encodable. A model that looks like this:

import Gloss

struct MyModel: JSONEncodable {
    let id: Int?
    
    func toJSON() -> JSON? {
        return jsonify(["id" ~~> self.id])
    }
}

adds

extension MyModel: Encodable {

    func encode(to encoder: Swift.Encoder) throws {
        // Proper Encodable defintion or throw GlossError.encodableMigrationUnimplemented
        // Remove this method if Codable can synthesize encoding for you
    }

}

Translating Model Objects to JSON

Where translating to JSON currently looks like this:

let json: JSON? = myModel.toJSON()

it becomes:

let json: JSON? = myModel.toEncodableJSON()

JSON Arrays

Similar usage applies to arrays of Decodable and Encodable models, with from(decodableJSONArray:) and toEncodableJSONArray() respectively.

Configuring JSONDecoder and JSONEncoder

If your Codable definitions are sound but you're encountering Codable errors, make sure your JSONDecoder or JSONEncoder instances are configured properly and pass them at call-sites:

let mySharedJSONDecoder: JSONDecoder = ...
let myModel: MyModel = .from(decodableJSON: someJSON, jsonDecoder: mySharedJSONDecoder)
let mySharedJSONEncoder: JSONEncoder = ...
let json: JSON? = myModel.toEncodableJSON(jsonEncoder: mySharedJSONEncoder)

Using Data Instead of JSON to Create Models

In the places where you've come to rely on Gloss's JSON type, you'll eventually need to pass Data, as that is what Codable uses. To get a jump using decode(:), one option is use the same method Gloss uses to do Data transformation:

import Gloss

let sharedGlossSerializer: GlossJSONSerializer = ...
let json: JSON = ...
if let data: Data? = sharedGlossSerializer.data(from: json, options: nil) {
    let myModel: MyModel = try? myJSONDecoder.decode(MyModel.self, from : data)
    ...
}

Take the opportunity with this migration to pare your models down to the slim amount of code Codable needs to work its magic and detangle your networking code from the details of JSON serialization. Future you will be grateful! ๐Ÿ”ฎ

โœจโœจโœจEOFโœจโœจโœจ

gloss's People

Contributors

4ch7ung avatar andrewjmeier avatar andrewsb avatar askielboe avatar bachino90 avatar bojan avatar ejmartin504 avatar fabb avatar gerbiljames avatar hcanzonetta avatar hkellaway avatar jkandzi avatar jlmendezbonini avatar kampro avatar karpelcevs avatar maximveksler avatar morganchen12 avatar mvdevries avatar nuudles avatar orta avatar rahul0x24 avatar rbukovansky avatar readmecritic avatar ryanschneider avatar urosk avatar vkotovv avatar wanderingstar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gloss's Issues

Using Gloss with nested object of same type of its father

Hello guys,

I'm using Gloss in my project and I gotta say that this library is awesome, but I've been struggling with a JSON which contains nested a object which are equally of its father.

Here's an example:

categories: {
        param: "category",
        multiple: true,
        values: [{
                    children: [{
                        label: "Galerias",
                        value: "galerias",
                        is_selected: false,
                        is_parent_of_selected: false,
                        result_count: 1
                    }, {
                        label: "Shows",
                        value: "shows",
                        is_selected: false,
                        is_parent_of_selected: false,
                        result_count: 1
                    }],
                    label: "Artes",
                    value: "artes",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 2
                }, {
                    label: "Auto",
                    value: "auto",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 3
                }, {
                    label: "Bares",
                    value: "bares",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 9
                }, {
                    label: "Comรฉrcio",
                    value: "comercio",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 17
                }, {
                    label: "Consultoria Administrativa",
                    value: "consultoria-administrativa",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 1
                }, {
                    children: [{
                        label: "Apresentaรงรฃo",
                        value: "apresentacao",
                        is_selected: false,
                        is_parent_of_selected: false,
                        result_count: 1
                    }],
                    label: "Cultura e Entretenimento",
                    value: "cultura-e-entretenimento",
                    is_selected: false,
                    is_parent_of_selected: false,
                    result_count: 1
                },

As you can see , some of my categories have children and I'm wondering how I'm going to represent it in my Gloss Model. Can you please give me a light on it?

Thanks in advance,
Renan.

[Solved] Using Gloss with [] object

Super work with Gloss.

I'm just don't get it how to deserialize an objet like this :

{
  "kind": "books#volumes",
  "totalItems": 5,
  "items": [
    {
      "id": "hqKfQwAACAAJ",
      "volumeInfo": {
        "title": "\"I Ain't Yo Bitch\"",
        "authors": [
          "Jabulile Bongiwe Ngwenya"
        ],
        "industryIdentifiers": [
          {
            "type": "ISBN_10",
            "identifier": "0733426093"
          },
          {
            "type": "ISBN_13",
            "identifier": "9780733426094"
          }
        ], [...]
}},
   {
      "id": "hq5JhbP", [...]
}
]

In my case I need the very first "items" only but I want to know also how to get an array of each response.
If I understand well I need to make a struct items with :

init?(json: JSON) {
        guard let data: JSON = "items" <~~ json else {
            print("Error no JSON data available")
            return nil
        }

}

and do an other struct bookwith to get [book]. But I don't know how to do to get them.

Is it clear enough for you

How to decode mixed items

I need some help to use your great lib to fit my need.
Here is the situation.
The application received from a server a JSON file containing a timeline.
A timeline is made of 2 kinds of item (called TimelineItem):

  • Header
  • Session

As there are common properties between both Header and Session, I created a TimelineItem protocol, implemented by Header and Session.
With Unit Tests I checked that those structs can be created successfully from JSON files.

But I am stucked on how to decode the timeline JSON.

Here is the format of the timeline.json :

{
    "timeline": [{
        "id": 1,
        "type": "header",
        "startDate": "2016-06-06T08:30:00+02:00",
        "text": "8H30 โ€” 9H30"
    }, {
        "id": 2,
        "type": "session",
        "name": "session title",
        "room ": "room name ",
        "startDate ": "2016 - 06 - 06 T08: 30: 00 + 02: 00 ",
        "duration ": 40
    }, {
        "id": 3,
        "type": "header",
        "startDate": "2016-06-06T09:30:00+02:00",
        "text": "9H30 โ€” 10H30"
    }, {
        "id": 4,
        "type": "session",
        "name": "session title",
        "room ": "room name ",
        "startDate ": "2016 - 06 - 06 T09: 30: 00 + 02: 00 ",
        "duration ": 40
    }]
}

Here are the struct:

struct Header: TimelineItem, Decodable {
  // *********************************************************************
  // MARK: - Public properties
  let id: Int
  let type: TimelineItemType = .Header
  let startDate: NSDate
  let text: String

  // *********************************************************************
  // MARK: - Initializer
  init?(json: JSON) {
    guard let id: Int = "id" <~~ json,
      let type: TimelineItemType = "type" <~~ json,
      let startDate: NSDate = Decoder.decodeDateISO8601("startDate")(json),
      let text: String = "text" <~~ json where type == .Header else {
        return nil
    }
    self.id = id
    self.startDate = startDate
    self.text = text
  }
}
struct Session: TimelineItem, Decodable {
  // *********************************************************************
  // MARK: - Public properties
  let id: Int
  let type: TimelineItemType = .Session
  let startDate: NSDate
  let name: String
  let speaker: Speaker

  // *********************************************************************
  // MARK: - Initialiser
  init?(json: JSON) {
    guard let id: Int = "id" <~~ son,
      let type: TimelineItemType = "type" <~~ son,
      let startDate: NSDate = Decoder.decodeDateISO8601("startDate")(son),
      let name: String = "name" <~~ son,
      let speaker: Speaker = "speaker" <~~ json where type == .Session else {
        return nil
    }
    self.id = id
    self.startDate = startDate
    self.name = name
    self.speaker = speaker
  }
}

Here is the Timeline struct that does not work till now.

struct Timeline {
  let timelineItems: [TimelineItem]

  init?(json: JSON) {
    guard let timelineItems: [TimelineItem] = "timeline" <~~ json else {
      return nil
    }
    self.timelineItems = timelineItems
  }
}

How can I do to decode this mixed stream of struct?

Working with Arrays at the Root

Suppose i have array of URLS. I am trying to convert the below to NSURL objects but couldn't find any method.

[
    "http://google.com",
    "http://facebook.com"
]

But if i have a rootKey like the below json. I can use Decoder.decodeURLArray("urls")(json).

{ 
"urls" : [
    "http://google.com",
    "http://facebook.com"
]
}    

I guess JSON should be AnyObject instead of [String: AnyObject].

bool encoding to 1 / 0

Hey there,

Just wondered why the bool value type in Swift is encoded to 1, 0, and not true and false? Is there a setting to change this?

Cheers

Int32 type of var cannot be parsed using Gloss

I have a class variable which i need to take as Int32 and not Int

var systemType: Int32

when ever i try to parse this using

self.systemType = ("SystemType" <~~ dictionary)!

app crashed saying fatal error: unexpectedly found nil while unwrapping an Optional value

i can avoid the crash by if let but it will not parse the value.

"Consecutive statements on a line" when using <~~ operator

This software is rad and is saving my bacon, but for some reason it seems picky about spaces in using the <~~ operator...

If I do it like this it throws the above error.

self.id = "_id" <~~json

But if I get rid of all spaces it works without a hitch:

self.id = "_id"<~~json

But then the moment I put a space back in on one side, the "consecutive statements" complaint is back:

self.id = "_id"<~~ json

One space on each side, though, and it works fine. It took me a while to figure this out...

JSON property name with dot - ".meta"

Hi guys,
I need to parse JSON data that contains property named .meta. Other properties are parsed well but it seems that this particular name can't be parsed. My code is bellow.

struct MOSomeModel: Decodable {
    let meta: MOMeta?
    let data: MOData?

    init?(json: JSON) {
        self.meta = ".meta" <~~ json
        self.data = "data" <~~ json
    }
}

struct MOMeta: Decodable {   
    let currency: Currency?

    enum Currency: String {
        case Eur = "EUR"
    }

    init?(json: JSON) {
        self.currency = "currency" <~~ json
    }
}

Property named data is parsed well but meta property isn't. JSONData bellow.

{
    ".meta": {
        "currency": "EUR"
    },
    "data": {
        ... Something parsed well ...
    }
}

Simple Array

JSON:

[ { "nome" : "1" }, { "nome" : "2" }, { "nome" : "3" } ]

Object: [Using Realm]

class Object: Object, Decodable {
  dynamic var nome: String = ""
  public convenience init?(json: JSON) {
    guard let nome: String = "nome" <~~ json
      else { return nil }
    self.init()
    self.nome = nome
  }
}

Parsing from a file:

if fileManager.fileExistsAtPath(fullPath), let data = fileManager.contentsAtPath(fullPath) {
          if let array: [AnyObject] = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)  as? [AnyObject] {
            guard let obj = [Object].fromJSONArray(array) else { //error here
              return []
            }
         return obj

can't use lib when prase json from string

Nice lib, but I have problem when use that to parse json from string

let stringData:NSString = "{\"msgCode\":1,\"msgContent\":\"Success\",\"result\":{\"listThread\":[{\"id\":\"14588730530526otdw\",\"threadId\":\"1457965565616y5Blg\",\"content\":\"comment\",\"status\":0,\"timeCreate\":1458873053052,\"userId\":\"admin\"},{\"id\":\"14588382362644XDaF\",\"threadId\":\"1457965565616y5Blg\",\"content\":\"sdafsd gsdf\",\"status\":0,\"timeCreate\":1458838236264,\"userId\":\"null\"}],\"total\":16},\"timeServer\":1459236558851,\"s\":0}";

and I used lib like that
let jsonData:NSData = stringData.dataUsingEncoding(NSUTF8StringEncoding)!; do{ let jsonDic = try NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers) as! [String: AnyObject]; guard let testObj = TestObj(json: jsonDic)else{ print("[\(NSURL(fileURLWithPath:#file).lastPathComponent! as String): \(#line)] >> \(#function): ERROR"); return } }catch let error{ NSLog("[ %@ : %d] %@ > ERROR: %@", #file, #line, #function, "\(error)"); }

with TestObj as file attachment
TestObjc.txt

But when i run it my testObj.result.listThread.count == 0? Can't get any object from listThread?

and when i try with json
let testData = ["msgCode":1,"msgContent":"Success","result":["listThread":[["id":"14588730530526otdw","threadId":"1457965565616y5Blg","content":"comment","status":0,"timeCreate":1458873053052,"userId":"admin"],["id":"14588382362644XDaF","threadId":"1457965565616y5Blg","content":"sdafsd gsdf","status":0,"timeCreate":1458838236264,"userId":"null"]],"total":16],"timeServer":1459236558851,"s":0]

it's fail too!

Thanks for lib!

NSManagedObject and Gloss interaction?

I've been researching possible JSON mapping libraries, and have been trying to come up with a solution that will allow me to map the JSON into CoreData models. I have seen several object mapping libraries that struggle when hydrating a CoreData model (implements the NSManagedObject protocol) through the library

Is this something that Gloss allows?

Is there a way to include javascript null in arrays?

I have a charting library that can accept an array of numbers, but if I want to specify a blank datapoint, I need to specify it with null. Is there a way in gloss to output a JSON Array like so:

{
"data": [12,23,null,15,25]
}

json integer not decoded as Int

I'm 99% certain this is not a Gloss issue, but I thought I'd ask the question here to see if anyone else has experienced this with Swift/JSON.

I am calling a Flickr API which returns the following JSON (snippet):

(Please note that the snippet is the output from a print of a JSON object (map) which is defined [String:AnyObject]).

{ person = { "can_buy_pro" = 0; description = { "_content" = ""; }; "has_stats" = 0; iconfarm = 2; iconserver = 1523; ... }

Note the two fields: 'iconfarm' and 'iconserver'. They are clearly JSON integers.

When I used the following Gloss code:

guard let iconServer: Int = "person.iconserver" <~~ json, let iconFarm: Int = "person.iconfarm" <~~ json else { return FlickrDefaultBuddyIconUrl }

iconFarm was correctly converted to the integer 2 and iconServer was nil.

When looking at the Gloss code, I found it ultimately boiled down to code such as the following:

if let iconserver = person["iconserver"] { let x = iconserver as? Int print("x: \(x)") }
When I looked more closely, I find iconserver is of type NSString, but iconfarm is NSNumber.

I added the following:
let y = Int((iconserver as? String)!)
which correctly converts the iconserver NSString to an Integer.

Is this a Swift issue?

Has anyone experienced anything like this? Could there be something in the JSON string on the wire that confuses the JSON parse? If so, what's the best way to get the raw NSData returned by the NSURLRequest in printable form?

Note: I'm using OAuthSwift as my network request library.

Issue when using nested keypaths when compiling with optimization + Swift 2.2

With Swift 2.2, I've run into an issue when decoding deep json using the dot syntax. The decoding crashes with the error:

Gloss was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) 

The following test case fails with the above error:

import XCTest
import Gloss

class GlossTestTests: XCTestCase {

    func testExample() {
        let json = [
            "foo":["bar":"woo"]
        ]
        let woo = FooBar(json: json)?.woo ?? "none"
        print(woo)
    }

}

class FooBar: Decodable {
    let woo: String?

    required init?(json: JSON) {
        self.woo = "foo.bar" <~~ json
    }
}

I'm not sure if I'm missing something, but everything seemed ok with Swift 2.1.

The watchOS platform

Hello!

Is there any reason why watchos isn't listed as a supported platform in Gloss.podspec?

If not, could the podspec be updated with the following:

s.platforms = { :ios => "8.0", :osx => "10.9", :tvos => "9.0", :watchos => "2.0" }

Happy to fork and submit a P.R. if you'd prefer.

Thanks!

How to deserialise native type arrays

Hi, I'm new to Gloss and I struggle deserialising native object arrays.

For example I want to deserialise this object

{
   name: "Duffycola",
   values: [1,2,3,4,5]
}

I don't see how I would correctly extend Int to conform to the Decodable protocol, because the individual object "1" has no "key" and no enclosing brackets in the json. I think the problem is the fact that Decoder.decode() requires a key. Would it be possible to add a Decoder.decode method which simply casts the given string to Int?

extension Int : Decodable
{
    public init?(json: JSON) {
        guard let value : Int = "" <~~ json
        else { return nil }
        self.init(value)
    }
}

Second, the documentation gives as an example how to deserialise a collection of objects, meaning the array starts at the root. In this example, however, the array is a subpath. I thought of doing something like this, but I'm not sure:

guard let durations: [Int] = Int.modelsFromJSONArray(("values" <~~ json)!)

Missing file in 0.7.0

Seems like there is a a missing file (Dictionary.swift), or that this should be removed from the build ?

*** Fetching Gloss
*** Checking out Gloss at "0.7.0"
*** xcodebuild output can be found in /var/folders/qj/_6jn0qb931n9f5t_xg5d52pw0000gn/T/carthage-xcodebuild.xJJzcc.log
*** Building scheme "Gloss" in Gloss.xcodeproj
** BUILD FAILED **


The following build commands failed:
    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
(1 failure)
<unknown>:0: error: no such file or directory: '/Users/nmodin/dev/github/ScoreCard/Carthage/Checkouts/Gloss/Sources/Dictionary.swift'
A shell task failed with exit code 65:
** BUILD FAILED **


The following build commands failed:
    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
(1 failure)

ContainObjects function unclear

Exist a equivalent for this function in objects type glossy.

if found
contains(<#T##predicate: (object) throws -> Bool##(object) throws -> Bool#>)

But i don't understand how works.

Can help me?

Decoding a polymorphic model

Does Gloss support decoding a polymorphic model?

For example, I have JSON like this:
{"MyProp": "1234567890","MyList": [{"Type": "A","AProp": "A Field"},{"Type": "A","BProp": "B Field" }]}

MyList is a list of items of different sub types, and I'd like the decoder to be able to create the proper types based on the value of the "Type" field.

What's the best way to approach this?

fyi, I'm using Jackson (https://github.com/FasterXML/jackson) in the Java world, and they do this by annotating the parent class to indicate which sub class to map for each value

Thanks,

John

Generic Object Mapping :: Feature Request

{
"success": true,
"data": {
/*
Server sends result object as response in "data" key.
Result object could be AnyObject depending upon the Rest API fetched.
*/
},
"error": {
}
}

Above I wrote a JSON skeleton of generic server response. In "data" key server may send any object as per API requested. I need put a provision to mapping any object to desire object. Is there any feature already present in Gloss ?

set default values

If the key gets nil, I would like to give a default value.

This is possible?

Int64 fails to decode

Sorry, I'm a complete newbie here. Seems like only NSNumber or Int works properly. If I use Int64, the cast in Decoder.decode fails. This is the workaround I used;

func decodeInt64(key: String) -> JSON -> Int64? {
    return {
        json in

        if let number = json[key] as? NSNumber {
            return number.longLongValue
        }

        return nil
    }
}

Int64 encoding failure

when trying to encode an object

struct ConfigurationMetadata: Encodable {
    let protocolVersion: String
    let timestamp: Int64
    let appId: String
    let appVersion: String
    let cardIdType: String

    func toJSON() -> JSON? {
        return jsonify(
            [
                "protocolVersion" ~~> self.protocolVersion,
                "timestamp" ~~> self.timestamp,
                "appId" ~~> self.appId,
                "appVersion" ~~> self.appVersion,
                "cardIdType" ~~> self.cardIdType
            ]
        )
    }
}

Field timestamp is omitted in the output JSON

Disappearing field when encoding dictionary

Hello,
I encounter a strange problem. Being new to Gloss, I may be using it the wrong way, but I'm puzzled by the way it works, so I wondered if it could be an issue.

Let's assume we have an encodable struct:

struct testStruct : Encodable {
    let attrib : String
    func toJSON() -> JSON? {
        return jsonify([
            "type" ~~> "TEST",
            "attrib" ~~> attrib
            ])
    }
}

The resulting json being an object containing two fields type and attrib.

Now let's create a dictionary of structs:

let dict = [
    "a":testStruct(attrib:"First"),
    "b":testStruct(attrib:"Second")
]

Finally I jsonify my final object with that code:

jsonify([
    "field" ~~> "Hello",
    "disapearingField" ~~> dict
])

Here what I get:

{
    "field": Hello, 
    "b": {
        attrib = Second
        type = TEST
    }, 
    "a": {
        attrib = First
        type = TEST
    }
}

I was expecting something like that:

{
    "field": Hello, 
    "disapearingField": {
        "b": {
            attrib = Second
            type = TEST
        }, 
        "a": {
            attrib = First
            type = TEST
        }
    }
}

So is that a functionality and I do not use Gloss the way it should be, or is that a bug?

Thanks in advance

Array of mixed types

Is it possible to parse arrays that contain mixed types?

For example in my JSON I have this array:

"actiontasklist": [
  { "actiontype": "play_sound", "id": "VO1" },
  "INTERACTION_BLOCK"
]

What would be the best solution to parse this array or what would be my options?

Implementing Gloss protocol requires a class to be declared final

this takes away any possibility of inheritance for similar classes e.g. Product and ProductDetail.

Since Product will have to be declared final, ProductDetail would end up replicating all the fields of Product.

I have no idea on how to fix it, or if it is even possible. I couldn't find a similar ticket in the closed issues so putting it on the radar.

@hkellaway your thoughts please.

Serialization of Superclass properties

`

class A {

    var foo:String?

    public override func toJSON() -> JSON? {
        return jsonify([
            "foo" ~~> self.foo
            ])
    }
}


class B:A {

    var bar:String?

    public override func toJSON() -> JSON? {
        return jsonify([
            "bar" ~~> self.bar
            ])
    }
}

So If I do this...

let b = B()
b.foo = "foo"
b.bar = "bar"

let json = b.toJSON()

print(json)

I get:
["bar":"bar"]

I am forced to jsonify the foo property inherited by class A within class B. It would be great if the responsibility of serializing inherited properties was delegated to the superclasses. Thoughts?

Using Generic with Glossy Model

Hi,

When i implement a generic. My compiler breaks with the following error

Command failed due to signal: Segmentation fault: 11

  1. While emitting IR SIL function @TFV8Project8ResponseCurfMGS0_q__FT4jsonGVSs10DictionarySSPSs9AnyObject___GSqGS0_q__ for 'init' at /Users/rahulkatariya/Developer/Project/Models/_Response.swift:22:5

Sample Code:

import Gloss

struct Response<T> {
    var errorMessage: String?
    let status: Bool
    var data: T?
}

extension Response: Glossy {

    init?(json: JSON) { 
        guard let status: Bool = "status" <~~ json else { return nil } 

        self.errorMessage = "errorMessage" <~~ json 
        self.status = status
        self.data = "data" <~~ json
    }

    func toJSON() -> JSON? {
        return jsonify([ 
            "errorMessage" ~~> self.errorMessage,
            "status" ~~> self.status,
            "data" ~~> self.data
        ])
    }

}

Why are empty arrays encoded as nil?

Out of curiosity, why are empty arrays encoded as nil as seen on this line:

return encodedArray.isEmpty ? nil : [key : encodedArray]

Wouldn't you want the encoded JSON to closely mirror what's being encoded?

modelsFromJSONArray(jsonArray:) should return [Self] instead of [Self]?

In the implementation of the method in the extension to Decodable, it will always return an array, even if it's empty:

static func modelsFromJSONArray(jsonArray: [JSON]) -> [Self]? {
        var models: [Self] = []

        for json in jsonArray {
            let model = Self(json: json)
            if let model = model {
                models.append(model)
            }
        }

        return models
    }

I bring this up only because I've run into a lot of annoying places where I am forced to either "if let
or force unwrap when working with JSON arrays.

Happy to PR it if you agree with the change.

The ISO 8601 date tests fail when ran in different time zones

When running the tests on time zones different than the one the test was written, they fail when parsing the hour.

For example, in testDecodeDateISO8601 in DecoderTests.swift, the object's hour is 21 UTC, the tests check for 17, but when running in continental Europe the test fails since the hour is translated into 23 CEST.

Make Encodable extend CustomStringConvertible

In all of the Gloss models I have I found myself doing this:

var description: String {
    return toJSON()!.description
}

Have you considered making Encodable inherit the CustomStringConvertible protocol and provide a default implementation for description similar to the one above?

Runtime check of Decodable/Encodable when using gloss models in Generics

Suppose I have a Generic Response Class like below

import Gloss

struct GenericResponse<T>: Glossy {

    var errorMessage: String?
    var status: Bool?
    var data: T

    init?(json: JSON) { 
        guard let data: T = "data" <~~ json else { return nil } 

        self.errorMessage =  "errorMessage" <~~ json
        self.status =  "status" <~~ json ?? false
        self.data = data
    }

    func toJSON() -> JSON? {
        return jsonify([ 
            "errorMessage" ~~> self.errorMessage,
            "status" ~~> self.status,
            "data" ~~> self.data
        ])
    }

}

And two JSON objects

  1. ["errorMessage": nil, status: true, data: "Some text goes here which is of type string and doesn't conform to Glossy"]
  2. ["errorMessage": nil, status: true, data: ["name":"This is a model which conforms to Glossy Protocol"]]

Now when I try to init the Generic Response method with 2nd JSON Object, It returns me nil as it calls the func Decoder.decode() -> JSON -> T?. To solve this issue I have to make my Generic in GenericResponse model conform to Glossy Protocol like struct GenericResponse<T: Glossy>: Glossy but then it gives error with the 1st JSON Object because the data is of type string and it doesn't conform to Glossy.

I was able to solve the problem at the time of encoding.

I created a Protocol

struct AnyEncodable: Encodable {

    let value: Encodable

    func toJSON() -> JSON? {
        return value.toJSON()
    }

}

and then tweak the function Encode

public static func encode<T>(key: String) -> T? -> JSON? {
    return {
        property in

        if let property = property as? Encodable {
            return encodeEncodable(key)(AnyEncodable(value: property))
        } else if let property = property as? AnyObject {
            return [key : property]
        }

        return nil
    }
}

Reference:
http://stackoverflow.com/questions/35431712/generic-method-override-not-working-in-swift/35434838?noredirect=1#comment58569896_35434838

Is there any way i can work around this problem at the time of Decoding ?

How to pass the Decodable type variable

Hi I decode JSON into class A (decode in the function in class), just say A.customers, and when I print the content of this object it works fine

The problem is when I am at the viewcontroller, I cannot print that same object, the error is

fatal error: unexpectedly found nil while unwrapping an Optional value

PS : the source which is type of JSON, is passable to the viewcontroller btw

Am I doing it wrongly?

Decode array of URLs

right now this would fail

let imageURLs:[NSURL] = ("imageURLs" <~~ json)!

we have to do this instead:

// Get an array of strings first
let imageURLStrings:[String] = ("imageURLs" <~~ json)!
// now convert it to an array of URLs manually
var imageURLs:[NSURL] = []
for var i = 0; i < imageURLStrings.count; i++ {
    let currentURL = NSURL(string: imageURLStrings[i])!
    imageURLs.append(currentURL)
}

I'll try to figure out how to do it in Gloss and submit a PR. Or if it's a quick fix, I'll let @hkellaway take care of it.

How is this any different from Mantle?

Seems like now we're just fragmenting the people who need this sort of library into the two libraries. This library, if it should exist in lieu of Mantle, should have an explanation of how it's different and the pros and cons of the two.

Problem with generic type

So, I have json like this, data inside result sometimes is string, sometimes is an object

{
    "status": "success",
    "message": "",
    "result":
    {
        "test_result": "Blah blah blah"
    }
}

Here is my code

struct Response<T>: Decodable {
    let status: String?
    let message: String?
    let result: T?

    init?(json: JSON) {
        self.status = "status" <~~ json
        self.message = "message" <~~ json
        self.result = "result" <~~ json
    }
}
struct TestResponse: Decodable {
    let testResult: String?

    init?(json: JSON) {
        self. testResult = "test_result" <~~ json
    }
}
Alamofire.request(.GET, url)
    .responseJSON { response in
        if let json = response.result.value as? [String: AnyObject] {
            guard let testObj = Response<TestResponse>(json: json) else {
                print("Error initializing object")
                return
            }
            debugPrint(testObj)
        }
}

And the result is always nil T_T, did I do something wrong here?

Class Clusters

Is support for class clusters planned?

I'm aware that Gloss is favorably used with structs. Though we have a use case where the server has a class hierarchy of DTOs, and the specific subclass can be derived from one property.

At the moment we use Mantle, but we investigate into other lightweight modeling frameworks that can also take advantage of Swift structs.

In this specific use case, we thought about just squashing all the subclasses' properties into one struct, but that just gets overcrowded, and in the code it's not obvious anymore which property sets belong to each other and need to be filled together - also when serializing to json, it's not allowed to send properties not present in the according original subclasses' serverside DTO.

Other suggestions than class clusters are welcome too!

Do not create NSDateFormatter on each decoding/encoding operation

NSDateFormatter (and NSFormatter in general) costs a lot to create.
In order to improve performance, it is better to keep a single instance of it as a global property.

Furthermore, it could be useful to make public the formatter and related date formats used by Gloss.

fromJSONArray

Hi,

From the examples.
Something like below will give compiler errors for Swift 2.2, because fromJSONArray returns [RepoOwner] and not an optional. So checking for something going wrong here doesn't seem to work?

guard let repoOwners = [RepoOwner].fromJSONArray(repoOwnersJSON)
    else { /* handle nil array here */ }

I think it makes sense to add throws for fromJSONArray in case of errors. From what I understand for example Freddy does something like this and I think something similar help make this safer?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.