utahiosmac / marshal Goto Github PK
View Code? Open in Web Editor NEWMarshaling the typeless wild west of [String: Any]
License: MIT License
Marshaling the typeless wild west of [String: Any]
License: MIT License
We should come up with a name that wont conflict with existing objects in apples frameworks.
It'd be great if you could update the Cocoapods repo.
I could use a suggestion on how to best provide progress when parsing a JSON array of a zillion records. Been using the frameworks simple syntax to unmarshal the array with my object implementing Unmarshaling protocol. Works perfectly fine, but when I have many records, how can I provide a 'percent complete' back to the user?
`
// This one liner blasts thru the millions of elements in my JSON array to unmarshal,
// but doesn't let me know which index its on so I can give the user progress feedback.
let records: [MyRecord] = try? jsonObject.value(for: "BillonsOfRecords")
`
I'm updating my app to Swift 3.1 and I ran carthage update
after installing Xcode 8.3 and swift 3.1.
While building Marshal if fails with the following: <unknown>:0: warning: argument unused during compilation: '-iapinotes-modules /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/arm64'
I don't think it is Marshal specific because I checked out the Marshal repo and it builds fine. However, this is the only framework where I get this error. Any ideas of how I can work around this warning? Internet search says to pass -Qunused-arguments
but is that possible with Carthage?
It would be nice to have built in support for marshaling arrays of optionals. That way if an object in an array fails to initialize/throws during initialization it doesn't throw out the entire array.
We already have support to create new objects and so it seems logical that we add a protocol for updating/configuring existing objects.
Something like the following:
public protocol ObjectConfigurable
{
func configure( object: Object )
}
In case there are situations where another dataType comes along that doesn't fall under our current dictionary extension, it would be helpful for users to utilize the existing code to write their own dictionary extensions to handle that dataType. For example, we don't currently support the Swift Set
type and so users are left to manually extract as an Array
and then pass it to the Set
constructor.
We should change private func anyForKey
to public func anyForKey
Hello,
I'm having some trouble unmarshalling some JSON that has a field that looks like:
{
"people" : {
"person_id1": {
"name": "some_name1"
"birthday": "19/2/90"
},
"person_id2": {
"name": "some_name2"
"birthday": "10/1/88"
},
"person_id3": {
"name": "some_name3"
"birthday": "30/6/92"
}
}
}
After parsing the JSON response, i'm trying to unmarshal it into my model like so:
let people: [String: Person] = json.value(for: "people")
But it keeps failing with the typeMismatchWithKey
error with:
key = people
expected = Person
actual = __NSDictionaryI
I'm not too sure what I'm doing wrong -do I need to write a custom valueType extension to unpack this like in the Readme?
Initial setup for codecov has been added to the travis.yml file but we need to make sure its working.
Hello,
Very interested in using Marshal however I'm not sure how best to handle JSON where the top level structure is an array rather than a dictionary.
We have some JSON that looks like this:
[
{
"id": "111",
"firstname":"John",
"surname": "Doe"
}, {
"id": "222",
"firstname":"Jane",
"surname": "Doe"
}
]
We would like to be able to map this directly into say an array of Users where User conforms to Unmarshaling i.e.
struct User: Unmarshaling {
var id: Int
var firstname: String
var surname: String
init(object: MarshaledObject) throws {
id = try object.value(for: "id")
firstname = try object.value(for: "firstname")
surname = try object.value(for: "surname")
}
}
However the library seems to always need a key in order to create the unmarshaled object. The only way I can see to do this now is to have something like:
var jsonObjects: [JSONObject] = try! JSONParser.JSONArrayWithData(data)
for obj in jsonObjects {
let user = User()
user.id = try obj.value("id")
user.firstname = try obj.value("firstname")
user.surname = try obj.value("surname")
}
This does not seem as elegant as being able to create the array of users directly i.e.
let users: [User] = try json.value("users")
What is the best way of handling this kind of JSON format using Marshal?
Thanks
We should add support for CocoaPods
i like the code design, but not like the name "UnmarshalingWithContext " for class
We are missing the following:
Int8
Int16
Int32
UInt8
UInt16
UInt32
UInt64
Character
Float80 - This isn't available on all platforms and so we may not want to include it.
Hi, I really like your approach with Marshal and I wanted to implement it in my project.
However, I'm currently using core Data and my objects are NSManagedObjects.
I'm trying to find a way to coexist Marshal and Core Data, but I haven't found any working solution yet. Did you already tried something similar?
Thanks a lot
When looking at the differences between Unbox and Marshal, I was surprised to see the UnmarshalingWithContext
protocol not use an init like Unbox. Is there a reason for that? Seems a bit less elegant.
For reference:
public protocol UnboxableWithContext {
/// The type of the contextual object that this model requires when unboxed
associatedtype UnboxContext
/// Initialize an instance of this model by unboxing a dictionary & using a context
public init(unboxer: Unbox.Unboxer, context: Self.UnboxContext) throws
}
Hi guys, I really want to thank you for you awesome work, I think Marshal is the fastest and lightweight library to deal with JSON structures.
I'm facing a problem parsing a simple data structures:
"students": {
"mrngcm":{
"first_name":"John",
"last_name":"Doe",
"courses": {
"MAT": 28
}
}
...
}
Here my model class:
import Foundation
import Marshal
class Student: Unmarshaling {
var id: String
var firstName: String
var lastName: String
var courses: [String:Int]
required init(object: MarshaledObject) throws {
self.firstName = try object.value(for: "first_name")
self.lastName = try object.value(for: "last_name")
self.courses = try object.value(for: "courses")
}
}
let json: MarshalDictionary = try! JSONSerialization.jsonObject(with: dataFromString, options: []) as! MarshalDictionary
let students: [String: Student] = try! json.value(for: "students")
I don't exactly how to assign key to model id and additionally I'm getting and error while extracting courses dictionary: fatal error: try!' expression unexpectedly raised an error: Type mismatch. Expected type Dictionary<String, Int> for key: courses. Got '__NSArray0
Do you have any suggestion? Thank you so much
Hi!
I experienced a small problem when using enums as ValueTypes. I have an enum in a project defined as the following:
enum Week: Int {
case all = 0, even, odd
}
I implemented the ValueType extension as the following:
extension Week: ValueType {
public static func value(from object: Any) throws -> Week {
guard let raw = object as? RawValue else {
throw MarshalError.typeMismatch(expected: RawValue.self, actual: type(of: object))
}
guard let week = Week(rawValue: raw) else {
throw Error.outOfBounds(raw)
}
return week
}
}
When using this in a type that has a Week
property, I get the compiler error 'ambiguous use of X' where X is either <| or value(for:).
I fixed it by using this code in my type that is using Week
, but the solution is not that satisfiying. Do you have any other ideas?
let rawWeek: Int = try object <| "week"
guard let week = Week(rawValue: rawWeek) else {
throw Week.Error.outOfBounds(rawWeek)
}
self.week = week
Thanks in advance!
To help alleviate build issues, we should add support for travis CI so that we can verify builds before merging pull requests.
We recently updated to v0.9.6, and found that some parsing is now broken. Previously, we could do
let dictionary: [String: Bool] = try object <| key
Now, I have to do something more like:
guard let dictionary = try object.anyForKey(key) as? [String: Bool] else { throw _ }
Another example is that I previously did this without problem:
let dictionary: [String: [String: JSONObject]] = try object <| key
We have the discardErrors
flag for helping deal with arrays with invalid elements, but it isn't really documented.
I, unfortunately, have some API endpoints that return responses which are objects that I would like to unmarshal. So say I get something that's a user object back:
{"username": "eric", "id": 1}
From my API, I get this value as a [String: AnyObject], so there is no opportunity to call .value()
on it. I simply want to convert it directly to an object.
Is the only option to re-wrap the [String: AnyObject] in another [String: AnyObject]? Or can I somehow unmarshal a [String: AnyObject] directly?
Hi,
I see a lot of issues around Cocoapods right now, and it stems from people not actually being able to access the podspec, without specifying the git url. In order to fix this then @psychoticidiot needs to run pod trunk push Marshal.podspec
.
This will release version 1.2.3 to cocoapods.org, and can then be found with a simple `pod 'Marshal', '~> 1.2'.
Right now you have to do: pod 'Marshal', :git => 'https://github.com/utahiosmac/Marshal.git'
.
I hope this clarifies things. If you want, you can add me as a maintainer of the pod, and I'll make sure it gets updated on Trunk.
Sometimes I get into a situation where Date parsing doesn't seem to work.
This:
self.createdAt = try json.value(for: "created_at")
Throws this:
Type mismatch. Expected type Date for key: created_at. Got '__NSCFString'
I can work around this by transforming to a string first, then to Date:
let s: String = try json.value(for: "created_at")
self.createdAt = try Date.value(for: s)
My Date support looks like so:
extension Date {
@nonobjc static let ISO8601SecondFormatter:DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ";
formatter.timeZone = TimeZone(abbreviation:"GMT")
return formatter
}()
static func fromISO8601String(_ dateString:String) -> Date? {
if let date = ISO8601SecondFormatter.date(from: dateString) {
return date
}
return .none
}
}
extension Date : ValueType {
public static func value(_ object: Any) throws -> Date {
guard let dateString = object as? String else {
throw MarshalError.typeMismatch(expected: String.self, actual: type(of: object))
}
guard let date = Date.fromISO8601String(dateString) else {
throw MarshalError.typeMismatch(expected: "ISO8601 date string", actual: dateString)
}
return date
}
}
It's not out yet, but putting this here as a reminder to implement generic subscripts
https://github.com/apple/swift-evolution/blob/master/proposals/0148-generic-subscripts.md
We have Array
and Dictionary
support. Set
is another core type we should support.
Hello together,
everythink worked fine. Then I added an other pod and deleted it again. And now I always get following error while importing
../ViewController.swift:11:8: No such module 'Marshal'
I also deintegrate and did pod init on my project. I still get the error.
What could be the Problem?
Do you have any suggestions for me to check?
Kind Regards
Alexander Niebuhr
We should add a separate target for OSX
please provide pod for your mapper project ๐๐ป
how to parse following ?
[
{"name": "alex","gender" : "male", "expertise_in" : "ios"},
{"name": "stacy","gender" : "female", "expertise_in" : "swift"},
{"name": "bob","gender" : "male", "expertise_in" : "objc"}
]
does if we don't able to parse this then there is any work around or does there is any plan for support it in future road map ?
Currently i am doing something like this
let objs : [JSONObject] = try JSONParser.JSONArrayWithData(response.data!)
let persons :[Person] = try objs.map({ (dict) -> Person in
return try Person(object: dict)
})
We should add a separate target for tvOS.
How to get value for key ".tag" from this JSON:
{
".tag": "test"
"name": "something"
}
Marshal splits the key by .
, so object.value(for: ".tag")
returns nil because tag
key is not found.
#68 Allows arrays of optionals so objects that fail to initialize will be result in optionals in the array. This would add functionality to drop nil values from arrays. Both this and #68 would enable the ability to serialize data that can be and discard that which can't be instead of throwing it all out. Addressing these two issues would add great flexibility to parsing arrays of objects while not breaking current behavior.
How can I unmarshall JSON that contains an array of different subclasses?
We're using ObjectMapper right now but I have some issues with the heavy use of unwrapped optionals and handling data validation.
We should add a separate target for watchOS
We should add a protocol to serialize data types into an Object
.
Something like:
public protocol ObjectRepresentable
{
var objectValue: Object { get }
}
I'm trying to marshal a property like:
var arrayOfArrayOfThings: [[Thing]]?
// ... later on ...
arrayOfArray = try object.value(for: "arrayOfArrayOfThings")
Where Thing
is a Unmarshaling
. But I get a No 'value' candidates produce the expected contextual result type '[[Thing]]?'
. I tried defining extensions to MarshableObject.value
that return [[A]]
but got stuck. It seems like for Array<Array<A>>
Swift doesn't recognize the inner Array<A>
type as a ValueType
?
We should add/verify support for carthage.
I have the JSON object:
{
"accountId" : 8954947,
"accountName" : "Primary",
"accountCurrency" : "USD",
"marginRate" : 0.05
}
I want to decode it to:
struct AccountSummary: Unmarshaling
{
let id: String
let name: String
let currency: Currency
let marginRate: Double
init(object: MarshaledObject) throws
{
try id = object.value(for: "accountId")
name = try object.value(for: "accountName")
currency = try object.value(for: "accountCurrency")
marginRate = try object.value(for: "marginRate")
}
}
id
throws Marshal.MarshalError error 3
because it only sees an Int
. How can I force it to read a String
Thanks for the great lib. I removed another older, less performant lib that served us well for a long time to move to this much lighter and flexible approach... and it's great.
Is there any way we can get the Podspec
version updates for releases? I use this in a stand alone http client dynamic lib. Would be great to get the fixes when you release them ๐
And maybe https://codebeat.co/
@bwhiteley @jarsen (and anyone else that wants to chime in)
We have been talking about making the core of this library generic. I just realized that we cant store native Swift data types (Int8, Int16, Int32, Int64, UInt, etc) since the values of MarshaledObject
have to be AnyObject
(which means all of our number extractions need to be adjusted to always pull values out of an NSNumber).
I have been thinking about how we might get data from any source. So, thinking along those line we also need to evaluate how we convert basic data types from one data type to another. Parsing JSON with odd formats might benefit from this, for example, a service might wrap some integer as a string and so instead of having the consumer pull out a string and then cast it as an integer, we could make use of the builtin data type conversions and do that for them automatically. This way the only time a consumer needs to do something like that is in those odd/rare cases.
I have been working on some initial code (attached) that would convert it over but I don't want to go too far until we have discussed it. I have passing unit tests written up as well and have tested it on mac and iOS (both 32bit & 64bit) for all data types. We would still need to adjust some additional code, for example the array extraction doesn't work if the values are Any
.
What do you think?
ValueType.swift.zip
We should lower the deployment target to support the prior iOS version. There is no technical limitation for us to exclude iOS 8.
Add Marshal to Swift Source Compat Suite: https://github.com/apple/swift-source-compat-suite
How can Marshal be extended to allow converting a JSON like this:
"somekey": ["s1", "s2", "s3"]
into this
"s1,s2,s3"
I had few multiple false starts already, can't figure it out.
I'm currently using Unbox but am seriously thinking of switching to Marshal. But it has one major problem for me. The way that Date
gets marshalling support by conforming to a protocol means I can't have dates parsed with different formatters. This is a real problem for applications that needs to parse JSON from different APIs that represent dates differently.
Any ideas of improving this?
@jarsen @bwhiteley
Is there a reason why the Int64
is being extracted from an NSNumber
? The underlying type for a Swift Int
is an Int64
and so you should be able to just extract and cast from an Int
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.