Moved to repository: https://github.com/Mailcloud/swift-serializer
-
-
Save turowicz/e7746a9c035356f9483d to your computer and use it in GitHub Desktop.
import XCTest | |
class Person:Serializable{ | |
var Name : String | |
var Surname : String | |
var Animals : Array<Animal> | |
init(Name:String, Surname:String) { | |
self.Name = Name | |
self.Surname = Surname | |
self.Animals = Array<Animal>() | |
} | |
} | |
class Animal:Serializable { | |
var Nickname : String | |
var Kind : String | |
init(Nickname : String, Kind : String) { | |
self.Nickname = Nickname | |
self.Kind = Kind | |
} | |
} | |
class SerializationTests: XCTestCase { | |
func test_serialization_works() { | |
var john = Person(Name: "John", Surname: "Doe") | |
john.Animals.append(Animal(Nickname: "Fluffy", Kind: "Dog")) | |
john.Animals.append(Animal(Nickname: "Purry", Kind: "Cat")) | |
println(john.toJson()) //will give binary data to include in HTTP Body | |
println(john.toJsonString()) //will give the exact string in JSON | |
//{"Surname":"Doe","Name":"John","Animals":[{"Kind":"Dog","Nickname":"Fluffy"},{"Kind":"Cat","Nickname":"Purry"}]} | |
var expected = "{\"Surname\":\"Doe\",\"Name\":\"John\",\"Animals\":[{\"Kind\":\"Dog\",\"Nickname\":\"Fluffy\"},{\"Kind\":\"Cat\",\"Nickname\":\"Purry\"}]}"; | |
XCTAssertEqual(john.toJsonString(), expected,"") | |
} | |
} |
I get line 20:
UnsafeMutablePointer<objc_property_t>' is not convertible to 'UnsafePointer<objc_property_t>
So I changed to UnsafeMutablePointer
hey guys sorry for not responding - been away for some time, will update the formatter to the most recent version later today - thanks for the input!
updated the code to my latest code base - will look into your points in the afternoon
Please be aware of this: http://imgur.com/Ihsrzci
An Int is a Bool and a Bool is a Int according to Swift. The same for Float and Double
Do you need release UnsafePointer
s? it doesn't have auto-release engine
Can you please add support for enumerations?
What are you considering the best way at the moment in Swift for deserializing the JSON back to a new object?
Any ideas to get optional properties like: var myNumber : Double?
This would allow a value to exist or not exist as happens in json...
For those of you who want a standard ISO8601 date format, change the date transformation lines to use this:
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
propertiesDictionary.setValue(dateFormatter.stringFromDate(date), forKey: propName)
@ziogaschr, I'm needing the same thing. The problem is that class_copyPropertyList(aClass, &propertyCount)
doesn't return enum type properties. Not sure why:
enum SeedType: Int {
case Seedless = 0
case Seeds = 1
case Pit = 2
}
class Fruit : NSObject {
var name = "Apple"
var id = 7
var date = NSDate()
var seedType = SeedType.Seeds
var parentFruit:Fruit?
}
var fruit = Fruit()
fruit.parentFruit = Fruit()
var propertyCount : CUnsignedInt = 0
let propertiesInAClass : UnsafeMutablePointer<objc_property_t> = class_copyPropertyList(fruit.dynamicType, &propertyCount)
println("property count: \(propertyCount)")
Results in:
property count: 4
The serialization result being:
{"id":7,"parentFruit":{"name":"Apple","id":7,"date":"2014-10-15T15:59:48.944"},"name":"Apple","date":"2014-10-15T15:59:48.937"}
This means that the enum property is getting skipped for some reason. I'm not sure how to get around that.
_Edit_
The answer is because "class_copyPropertyList only shows properties that are exposed to the Objective-C runtime" Source
So, it looks like this approach will not work for swift enums and optional value-types until Apple changes something.
@albertbori I have searched a bit on this topic too and finally I reached to same conclusion as you. :(
} else if propValue is NSNumber {
propertiesDictionary.setValue((propValue as Float), forKey: propName!)
}
is missing
@elecay made a good point regarding datatypes which no-one seems to have addressed. Any non-zero int value is returned as true. As a quick fix for now I've added the NSNumber line by @odemolliens and move bool down in the order of execution so it effectively never gets hit until I can write something to counter the problem.
In order to compile it from latest XCode, 2 changes are needed:
1 Change "propertiesInAClass" from UnsafePointer to UnsafeMutablePointer
2 Either force unwrap the propName, or use "if let" and wrap line 27 - line 49 in the "if let" block
that's awesome, I've been using reflection to get the type of value, i did not expect that can use setValue... Thank u
I've updated the code with my latest implementation.
Tomorrow I will convert it to a github repo so we all can contribute
Did you make the github repo? Seems like a good opportunity to merge all the suggestions.
Awesome job! I'll probably try to do something like that for querystrings. Would it be helpful somehow?
Great work - is there any way to do a deserialization also?
@turowicz nice work, it saves me a great time. You just forgot the type Int, Double and Float. Here is the code changed :
public func toDictionary() -> NSDictionary {
var aClass : AnyClass? = self.dynamicType
var propertiesCount : CUnsignedInt = 0
let propertiesInAClass : UnsafeMutablePointer<objc_property_t> = class_copyPropertyList(aClass, &propertiesCount)
var propertiesDictionary : NSMutableDictionary = NSMutableDictionary()
for var i = 0; i < Int(propertiesCount); i++ {
var property = propertiesInAClass[i]
var propName = NSString(CString: property_getName(property), encoding: NSUTF8StringEncoding)!
var propType = property_getAttributes(property)
var propValue : AnyObject! = self.valueForKey(propName);
if propValue is Serializable {
propertiesDictionary.setValue((propValue as Serializable).toDictionary(), forKey: propName)
} else if propValue is Array<Serializable> {
var subArray = Array<NSDictionary>()
for item in (propValue as Array<Serializable>) {
subArray.append(item.toDictionary())
}
propertiesDictionary.setValue(subArray, forKey: propName)
} else if propValue is Double {
propertiesDictionary.setValue((propValue as Double), forKey: propName)
} else if propValue is Int {
propertiesDictionary.setValue((propValue as Int), forKey: propName)
} else if propValue is Float {
propertiesDictionary.setValue((propValue as Float), forKey: propName)
} else if propValue is NSData {
propertiesDictionary.setValue((propValue as NSData).base64EncodedStringWithOptions(nil), forKey: propName)
} else if propValue is Bool {
propertiesDictionary.setValue((propValue as Bool).boolValue, forKey: propName)
} else {
propertiesDictionary.setValue(propValue, forKey: propName)
}
}
// class_copyPropertyList retaints all the
propertiesInAClass.dealloc(Int(propertiesCount))
return propertiesDictionary
}
@ALL we should turn it into a pod - I'll make a repo later
Moved to https://github.com/Mailcloud/swift-serializer
Please submit your pull request @nono67
Issues created for anyone who'd like to contribute https://github.com/Mailcloud/swift-serializer/issues?q=is%3Aopen+is%3Aissue
Firstly, this is awesome.
Just a couple of things I'd like to point out (modifications):
propValue.base64Encoding()
seems to be deprecated and caused me compiler errors. Changed it out for:propValue.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
That way, the same anti-cyclical referencing logic in Swift will prevent cyclical serialization of properties (leading to stack overflow)
3) Had to add NSDate serialization support on line 39:
All the credit for these ideas go to Porter Hoskins