Convert anything into anything in one operation; hex strings into UIColor/NSColor, JSON strings into class instances, y/n strings to booleans, arrays and dictionaries of these; anything you can make sense of!
Latest version requires iOS 8+ and Xcode 7.3+
- Installation
- The <-- Operator
- Convertible Protocol
- Deserializable Protocol (with JSON deserialization example)
- Serializable Protocol
Add the following line in your Podfile
.
pod "JSONHelper"
Add the following line to your Cartfile.
github "isair/JSONHelper"
Then do carthage update
. After that, add the framework to your project.
The <--
operator takes the value on its right hand side and tries to convert it into the type of the value on its left hand side. If the conversion fails, an error is logged on debug builds. If it's successful, the value of the left hand side variable is overwritten. It's chainable as well.
If the right hand side value is nil or the conversion fails, and the left hand side variable is an optional, then nil is assigned to it. When the left hand side is non-optional, the current value of the left hand side variable is left untouched.
Using this specification let's assume you have a dictionary response that you retrieved from some API with hex color strings in it, under the key colors
, that you want to convert into an array of UIColor instances. Also, to fully use everything we know, let's also assume that we want to have a default value for our color array in case the value for the key we're looking for does not exist (is nil).
var colors = [UIColor.blackColor(), UIColor.whiteColor()]
// Assume we have response { "colors": ["#aaa", "#b06200aa"] }
colors <-- response[colorsKey]
If your type is a simple value-like type, adopting the Convertible protocol is the way to make your type work with the <--
operator.
Example:
struct Vector2D: Convertible {
var x: Double = 0
var y: Double = 0
init(x: Double, y: Double) {
self.x = x
self.y = y
}
static func convertFromValue<T>(value: T?) throws -> Self? {
guard let value = value else { return nil }
if let doubleTupleValue = value as? (Double, Double) {
return self.init(x: doubleTupleValue.0, y: doubleTupleValue.1)
}
throw ConversionError.UnsupportedType
}
}
var myVector: Vector2D?
myVector <-- (1.0, 2.7)
While you can basically adopt the Convertible
protocol for any type, if your type is always converted from a dictionary or a JSON string then things can get a lot easier with the Deserializable
protocol.
Example:
class User: Deserializable {
static let idKey = "id"
static let emailKey = "email"
static let nameKey = "name"
static let avatarURLKey = "avatar_url"
private(set) var id: String?
private(set) var email: String?
private(set) var name = "Guest"
private(set) var avatarURL = NSURL(string: "https://mysite.com/assets/default-avatar.png")
required init(dictionary: [String : AnyObject]) {
id <-- dictionary[User.idKey]
email <-- dictionary[User.emailKey]
name <-- dictionary[User.nameKey]
avatarURL <-- dictionary[User.avatarURLKey]
}
}
var myUser: User?
user <-- apiResponse["user"]
// Serialization is coming soon. I'll probably not add a new protocol and just rename and update the Deserializable protocol and turn it into a mixin.
jsonhelper's People
Forkers
chatspry ashishnigam emmerson jeeliu leoliu3000 gitter-badger aldenhall erdiyerli lamudi-gmbh shaneafsar jameslyman aral justinyaoqi avalanched renming skywinder iossid carabina sarvex andym129 dylansale zyggit bluesea lancy you520t fly19890211 orta socialdesigner pixelcik mluedke2 milbai pannrays lovesunstar thiagoricieri hawkit jondwillis meh-uk rakutou prayagverma tvos-developers imex94 pluto-tv peymanmortazavi bbayhan mikhail001 alexiscreuzot diogoro solertis utsav475908 theakay dan89eu fullstackenviormentss mobiibom micnguyen nirzaf poojagupta-simformsolutions vissimo-group yaron3 trendingtechnology ajunlonglive kasukasu-collectionjsonhelper's Issues
NSURL does not get parsed
I used JSONHelper version 1.7.0 and it failed to parse NSURL provided. it used to work. I don't know what version I had before though. I also tried 1.6 and it didn't fix it.
import UIKit
import JSONHelper
var str = "Hello, playground"
struct TestModel : Deserializable {
var name : String?
var url : NSURL?
init(data: JSONDictionary) {
data
data["name"]
self.name <-- data["name"]
self.url <-- data["url"]
}
}
var t : TestModel?
let jsonString = "{\"name\": \"Rocket Raccoon\", \"url\":\"http://www.google.com\"}"
t <-- jsonString
t?.name
t?.url`
┆Issue is synchronized with this Asana task
CocoaPods: Xcode build error
Trying to build project with JSONHelper pod and got this error:
podfile:
source 'https://github.com/CocoaPods/Specs.git'
platform:ios, '7.0'
link_with ['ClubApp','ClubAppTests']
pod 'Facebook-iOS-SDK', '~> 3.20'
pod 'AFNetworking', '~> 2.4'
pod 'IOSLinkedInAPI', '~> 2.0'
pod 'JSONHelper', :git => 'https://github.com/isair/JSONHelper.git', :tag => '1.4.0'
console output:
Libtool /Users/ndelitski/Library/Developer/Xcode/DerivedData/ClubApp-bjvgmiummzkehjfcjiuntqrfglcl/Build/Products/Debug-iphonesimulator/libPods-JSONHelper.a normal x86_64
cd /Users/ndelitski/Repo/club/ClubApp.iOS/Pods
export IPHONEOS_DEPLOYMENT_TARGET=7.0
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static -arch_only x86_64 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.1.sdk -L/Users/ndelitski/Library/Developer/Xcode/DerivedData/ClubApp-bjvgmiummzkehjfcjiuntqrfglcl/Build/Products/Debug-iphonesimulator -filelist /Users/ndelitski/Library/Developer/Xcode/DerivedData/ClubApp-bjvgmiummzkehjfcjiuntqrfglcl/Build/Intermediates/Pods.build/Debug-iphonesimulator/Pods-JSONHelper.build/Objects-normal/x86_64/Pods-JSONHelper.LinkFileList -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -Xlinker -force_load -Xlinker /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a -Xlinker -add_ast_path -Xlinker /Users/ndelitski/Library/Developer/Xcode/DerivedData/ClubApp-bjvgmiummzkehjfcjiuntqrfglcl/Build/Intermediates/Pods.build/Debug-iphonesimulator/Pods-JSONHelper.build/Objects-normal/x86_64/Pods_JSONHelper.swiftmodule -framework Foundation -o /Users/ndelitski/Library/Developer/Xcode/DerivedData/ClubApp-bjvgmiummzkehjfcjiuntqrfglcl/Build/Products/Debug-iphonesimulator/libPods-JSONHelper.a
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: unknown option character `X' in: -Xlinker
Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static [-] file [...] [-filelist listfile[,dirname]] [-arch_only arch] [-sacLT] [-no_warning_for_no_symbols]
Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -dynamic [-] file [...] [-filelist listfile[,dirname]] [-arch_only arch] [-o output] [-install_name name] [-compatibility_version #] [-current_version #] [-seg1addr 0x#] [-segs_read_only_addr 0x#] [-segs_read_write_addr 0x#] [-seg_addr_table <filename>] [-seg_addr_table_filename <file_system_path>] [-all_load] [-noall_load]
Attaching file directly to project works fine, but i want to do this using CocoaPods, could you help please?
Non-Optional Deserialization
For cases when it is needed, JSONHelper should be capable of providing an easy way of assigning default values to properties in case deserialization fails.
[README] Add development section
README should have three main sections: Installation, Usage, and Development.
Implicitly unwrapped optional behavior
Hi,
I'm extremely new to Swift, so please forgive me if what's I'm trying to accomplish is a pure heresy, but why doesn't the following code work (just copy it into JSONHelperTests.swift to test it)?
func testBoolBang() {
var property: Bool!
property <<< dummyResponse["bool"]
XCTAssertEqual(property, true, "Bool property should equal true")
}
It should return "true" instead of "nil".
Am I wrong?
UIColor Deserialization
Support for deserializing color hex strings into UIColor objects.
var color: UIColor?
color <<< "#ff0000"
┆Issue is synchronized with this Asana task
Customizable Error Reporting
When deserialization fails for a property or an entire class, JSONHelper should provide an overridable error reporting functionality. The default function should log to console on debug builds, but it should be easily changeable into something like, say, reporting deserialization errors to services like Bugsnag.
Bugging
Bugging should be done
did this framework just can parse a array json?
my JSON String is :'{"status":true,"info":"OK","data":""}'
how parse?
┆Issue is synchronized with this Asana task
How to deserialize this?
How do I deserialize this JSON which is envenloped?
Timetable = (
{
ActivityId = 9847435321;
EndTime = "2014-11-24 11:00:00";
HomeWork = "";
Note = "";
RoomText = 148;
SchoolId = 71;
StartTime = "2014-11-24 10:10:00";
Status = Normal;
})
The following doesn't seem to work:
class Timetable: Deserializable {
var activityId: String?
var endTime: NSDate?
var homeWork: String?
var note: String?
var roomText: Int?
var schoolId: Int?
var startTime: NSDate?
var status: String?
required init(data: [String: AnyObject]) {
activityId <<< data["Timetable.ActivityId"]
}
}
JSON API support
┆Issue is synchronized with this Asana task
Nested Objects ?
Can this library deserialize nested objects ?
tvOS Support
Hello JSONHelper team,
I saw that on your podspec, you added the tvOS support on the master, 4 days ago.
However, there is no new version uploaded since then.
Do you think it could be possible to publish a 1.7.0 of JSONHelper library on Cocoapods in order to ship this feature ?
Best regards,
Lorenzo.
┆Issue is synchronized with this Asana task
Xcode 6.1 beta compile errors
Can't compile with these errors:
JSONHelper.swift:148:20: Value of optional type 'NSURL?' not unwrapped; did you mean to use '!' or '?'?
JSONHelper.swift:318:27: Value of optional type 'NSURL?' not unwrapped; did you mean to use '!' or '?'?
JSONHelper.swift:339:26: Value of optional type 'NSURL?' not unwrapped; did you mean to use '!' or '?'?
Adding "!" is creating another error, so I suppose it needs deeper analysis...
Time zone handling of NSDate conversions
Hi,
I am facing issue with datetime during parsing. I am getting UTC date in my server response and when i try to deserialize that, JSONHelper assume, it is system datetime.
for example, I am passing "2016-01-04 11:00:56" for deserialize which is UTC date. Now after deserialize, i am getting "2016-01-04 05:30:56 +0000" while it should be same "2016-01-04 11:00:56 +0000" And when convert in to string, it should show "2016-01-04 16:30:56"
My TimeZone is: 5:30+
Can you suggest, how can i achieve that? Where can I pass, date timezone info?
Thanks
Kamal Mittal
┆Issue is synchronized with this Asana task
Request: Object serialization to JSON string
It would be awesome to implement serialization of swift objects to JSON strings 👍
Is it possible to do so using this excellent library ?
Thank you...
┆Issue is synchronized with this Asana task
Support watchOS
Please share a scheme for Carthage
In order to use this lib with Carthage, you need to share a scheme. Here is how:
https://github.com/carthage/Carthage#share-your-xcode-schemes
Request: Changing Deserializable to require init? as oppose to init
When deserializing, I might pass a completely irrelevant object to init of a deserializable object and they have to handle it. having the option to return nil and say there are not enough information to initialize this object would be great specially since <-- operator does return an optional anyway.
┆Issue is synchronized with this Asana task
Should properties get set to nil if the JSON object doesn't contain the key?
Something I noticed in:
public func <<<<T>(inout property: T?, value: AnyObject?) -> T?
Is that it sets property = nil
in the event that value
is nil. Generally speaking, it'll be nil if the JSON object just doesn't contain that key at all. This can have the effect of changing whatever value was in your Swift object to nil if you receive a JSON payload that doesn't contain the key. I thought the common paradigm in JSON was to pass the key down but with a null object (NSNull
in Foundation-land) if you wanted to explicitly delete a value from an object on the clients.
Basically, my issue is this. Because my app receives JSON payloads from two sources, a web service API and a WebSocket, it has to be able to update existing object instances from a JSON payload. I've implemented it like:
public class User : ModelObject {
public var name: String?
public var handle: String?
public var createdAt: NSDate?
public var updatedAt: NSDate?
public required init(data: [String : AnyObject]) {
super.init(data: data)
updateWithJSON(data)
}
public override func updateWithJSON(data: [String : AnyObject]) {
super.updateWithJSON(data)
name <<< data["name"]
handle <<< data["handle"]
createdAt <<< data["created_at"]
updatedAt <<< data["updated_at"]
}
}
The response from the Web API is something like:
{
"id" : "38459979-e5f9-4c50-8bf6-8721bae33b4e",
"name" : "First Last",
"handle" : "first",
"created_at" : 1370263044,
"updated_at" : 1370263044
}
I'm successfully parsing this into a User object. Then, I get a payload from WebSocket like this:
{
"id" : "38459979-e5f9-4c50-8bf6-8721bae33b4e",
"name": "Something Else"
}
This now deletes the values that were stored in handle
, createdAt
and updatedAt
! I'm opening this as an issue instead of a pull request because I don't know what the consensus is on this kind of thing. Do people expect this deletion behaviour? If so, I'm happy to write a new operator that doesn't do the deletion, something like <<<=
maybe?
┆Issue is synchronized with this Asana task
CLong not interpretated on iPhone5
My object has CLong and it is not interoperated correctly on iPhone5/5c, it is working on any other devices. iOS 9.3
┆Issue is synchronized with this Asana task
Swift 1.2 Support
Hey there! XCode 6.3 was recently forced upon my machine and with it came Swift 1.2. JSONHelper doesn't comply with this new version of Swift, and I was wondering if there were any plans to update the library to be compliant. There don't seem to be a lot of changes required, but I don't want to duplicate work someone is already doing. I think I could make a PR, but my knowledge of Swift isn't great.
Not works with latest version of Xcode and Swift 2.2
I'm getting this error:
Module file was created by an older version of the compiler; rebuild 'JSONHelper' and try again:
┆Issue is synchronized with this Asana task
Don't require tuples passed to the deserialization operator to be named
JSON String Parsing
JSONHelper should be able to parse JSON strings and deserialize them as well. Which would make things like this possible:
class Person: Deserializable {
var name = ""
required init(data: [String: AnyObject]) {
name <<< data["name"]
}
}
var jsonString = "[{\"name\": \"I am\"},{\"name\": \"Groot!\"}]"
var people = [Person]()
people <<<<* jsonString
for person in people {
println("\(person.name)")
}
Support deserialization of JSON numbers to NSDecimalNumber
Basically explained by the title - it currently doesn't seem to be possible without adding an internal intermediate property which makes me sad.
┆Issue is synchronized with this Asana task
"application: JSONHelper" sometimes inserted for null values in JSON
We've got several computers using JSONHelper to parse JSON for Applescripts.
I've got some behavior that seems very strange to me.
Running the same version of the Applescript, and the same version of JSONHelper, on the same JSON data, on some computers it is returning the null values to Applescript as the name of the application. That is, the null values get returned as:
application "JSONHelper"
in the returned JSON data. This doesn't happen on other computers.
The files can be downloaded here:
https://www.dropbox.com/s/sgepla2fpspdnzq/JSONHelper_Issue.zip?dl=0
It's got the original JSON data, and the different responses returned by running that through JSONHelper on different computers. At least three computers are returning the version with "application: JSONHelper" substituted for all null values.
I'd appreciate any help/insight. Whatever's going on, I don't understand how I'm getting different results when I use the same JSON data with the same Applescript and the same version of JSONHelper.
Thanks in advance for any help.
Rename project
Find a more suitable name. We don't just help with JSON data anymore.
Date & URL Deserialization
JSONHelper should provide functionality that enables direct deserialization of JSON strings into NSDate and NSURL objects.
Discussion about new way of handling array/dictionaries
I've been doing a bit of experimentation for how to handle deserialization of arrays and dictionaries.
Basically instead of copy/pasting the implementation of primitives and tweaking it to have array support, let the array deserialization use the implementation of primitives. This means if later we decide to change the way we parse Dates, or handle floats, we need to change only one place in the code.
I'm still not happy with the implementation, since there're still some copy paste going on (#L262, #L273, #L284)
In terms of performance, it seems to not change anything, but more tests can be done for that.
Here is a comparison of old and new implementation. I ran the tests under each implementation about 10 times, and took the best number for each.
-
New:
Executed 24 tests, with 0 failures (0 unexpected) in 0.022 (0.036) seconds
-
Old:
Executed 24 tests, with 0 failures (0 unexpected) in 0.017 (0.045) seconds
To be honest I don't know what is the different between the number in brackets and the number before that.
https://github.com/lamudi-gmbh/JSONHelper/tree/array-map-experiment
┆Issue is synchronized with this Asana task
Utilize the new Codable protocol
New name
Poll: http://goo.gl/forms/zFWMsDvJQ5
JSONHelper doesn't cut it anymore, with 2.0.0 the library will mainly be centered around value conversion with additional support for converting data coming from APIs (regular REST, and JSON:API). Therefore, a new name is needed.
┆Issue is synchronized with this Asana task
Reimplementation JSONHelper with the magic of Generics
Hey.
I noticed that there are so many repeating code in JSONHelper, so I just reimplement most of it.
I try to use generics as much as I can to simplify the code, and now I make a little success.
With less then half the origin code, it can do the same things as before, even more features were added.
https://github.com/lancy/JSONHelper
It's compatible to most of the origin APIs, not all of them, but If you like it, I will make a pull request.
By the way, hope you don't mind that I'm planning to create another individual JSON Library to add more features (something like serialization), and It may refer some of your code. I will make a statements to thanks you and this project.
Have fun!
┆Issue is synchronized with this Asana task
Swift 2.0 support?
Hi @isair
I used JSONHelper in my personal project. And I'd like to upgrade it to iOS 9 and Swift 2.0. Do you have any plan to move?
How to handle in polymorphism
Suppose I have a base class named Accessory
, and there are some subclass inherit from it, like AudioAccessory
, LabelAccessory
, ContentAccessory
, and a type
to identify them.
class Accessory {
var type: Int
}
class LabelAccessory: Accessory {
var label: String
}
class ContentAccessory: Accessory {
var content: String
}
How do I convert a JSON into [Accessory]
?
Should I write my custom deserialisation function, switch type
to init object in different class? something like:
public func <-- (inout instance: [Accessory]?, dataObject: AnyObject?) --> [Accessory]? {
if let dataArray = dataObject as? [JSONDictionary] {
array = [Accessory]()
for data in dataArray {
let baseObject = Accessory(data: data)
switch baseObject.type {
case Label:
array!.append(LabelAccessory(data: data))
.....
}
}
} else {
array = nil
}
return array
}
Is there a better way to do that?
Thank you so much
[README] List out-of-the-box supported conversions
Under Xcode 7.3 NSDate? are interpreted as Int? by the Compiler causing NSDate? properties to not be set
The compiler appears to interpret NSDate? as Int? and thus setting NSDate? properties fails.
public func <-- <T>(inout property: T?, value: AnyObject?) -> T? {
var newValue: T?
""
if let unwrappedValue: AnyObject = convertToNilIfNull(value) {
// We unwrapped the given value successfully, try to convert.
if let convertedValue = unwrappedValue as? T {
// Convert by just type-casting.
newValue = convertedValue
} else {
// Convert by processing the value first.
switch property {
case is Int?:
if unwrappedValue is String {
if let intValue = Int("\(unwrappedValue)") {
newValue = intValue as? T
}
}
case is NSURL?:
newValue = NSURL(string: "\(unwrappedValue)") as? T
case is NSDate?:
if let timestamp = unwrappedValue as? Int {
newValue = NSDate(timeIntervalSince1970: Double(timestamp)) as? T
} else if let timestamp = unwrappedValue as? Double {
newValue = NSDate(timeIntervalSince1970: timestamp) as? T
} else if let timestamp = unwrappedValue as? NSNumber {
newValue = NSDate(timeIntervalSince1970: timestamp.doubleValue) as? T
}
default:
break
}
}
}
property = newValue
return property
}
Instead of reaching case is NSDate?:
, execution inside the switch enters case is Int?:
This problem occurs in Xcode 7.3.
┆Issue is synchronized with this Asana task
Warnings
I got the following warnings:
Conversion.swift:137:42: cast from 'NSDictionary?' to unrelated type '[T : AnyObject]' always fails
if let elements = rhs as? NSDictionary as? [T : AnyObject] {
~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
Deserialization.swift:122:42: cast from 'NSDictionary?' to unrelated type '[T : AnyObject]' always fails
if let elements = rhs as? NSDictionary as? [T : AnyObject] {
~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
┆Issue is synchronized with this Asana task
Support installation via Swift Package Manager
Swift 3.0 Support
Hello @isair ,
Do you plan to port your Pod on Swift 3.0 ?
All the best,
Lorenzo.
┆Issue is synchronized with this Asana task
Not able to use `let`
The readme says:
"// You can also use let instead of var if you want."
I don't find this to be the case. Changing a var x
to a let x
gives the error "Variable self.x passed by reference before being initialized".
How can I use let x
?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.