Created
June 25, 2014 07:49
-
-
Save mchambers/67640d9c3e2bcffbb1e2 to your computer and use it in GitHub Desktop.
A simple, limited model-to-JSON serializer in Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Here we'll use Swift's IDE-supporting reflect() | |
// function to build a basic JSON serializer. | |
// Per the fine engineers at WWDC, Swift's reflection support | |
// exists purely to support the IDE and the Playground. But | |
// we can have some fun with it anyway. ;) | |
class SerializerBase { | |
} | |
class BaseFruit: SerializerBase { | |
} | |
class FruitBasket: SerializerBase { | |
let banana=Banana() | |
let apple=Apple() | |
let grape=Grape() | |
} | |
class Grape: BaseFruit { | |
var name="Grape" | |
} | |
class Banana: BaseFruit { | |
var name="Banana" | |
var fruitType=2 | |
var delicious=false | |
var nutrients:Array<String>=["potassium"] | |
} | |
class Apple: BaseFruit { | |
var fruitType=1 | |
var name="Apple" | |
var delicious=true | |
} | |
var modelOut = Dictionary<NSString, Any>() | |
var theFruitBasket=FruitBasket() | |
func nsValueForAny(anyValue:Any) -> NSObject? { | |
switch(anyValue) { | |
case let intValue as Int: | |
return NSNumber(int: CInt(intValue)) | |
case let doubleValue as Double: | |
return NSNumber(double: CDouble(doubleValue)) | |
case let stringValue as String: | |
return stringValue as NSString | |
case let boolValue as Bool: | |
return NSNumber(bool: boolValue) | |
case let fruitValue as SerializerBase: | |
return toDictionary(fruitValue) | |
case let primitiveArrayValue as Array<String>: | |
return primitiveArrayValue as NSArray | |
case let primitiveArrayValue as Array<Int>: | |
return primitiveArrayValue as NSArray | |
case let objectArrayValue as Array<SerializerBase>: | |
// this be a tricky one | |
return NSNull() | |
default: | |
return nil | |
} | |
} | |
func toDictionary(model:SerializerBase) -> NSMutableDictionary { | |
var modelDictionary:NSMutableDictionary=NSMutableDictionary() | |
for var index=0; index<reflect(model).count; ++index { | |
let key=reflect(model)[index].0 | |
let value=reflect(model)[index].1.value | |
if key=="super" && index==0 { | |
// if the first key is super, we should probably skip it | |
// because it's most likely the reflector telling us the | |
// superclass of this model | |
// we'll need to handle this separately | |
// right now the else is only giving us the K/Vs from | |
// the current class. we need to also find a way to get | |
// them from the base class. | |
} | |
else { | |
if let nsValue=nsValueForAny(value) { | |
modelDictionary.setValue(nsValue, forKey: key) | |
} | |
} | |
} | |
return modelDictionary | |
} | |
let modelDictionary=toDictionary(theFruitBasket) | |
let modelJsonData:NSData=NSJSONSerialization.dataWithJSONObject(modelDictionary, options: NSJSONWritingOptions.PrettyPrinted, error: nil) | |
let modelJsonString=NSString(data: modelJsonData, encoding: NSUTF8StringEncoding) | |
println(modelJsonString) |
To get the properties from the base class, just iterate the Mirror provided by the super value. A basic function (don't use it as is, this is just a quick proof of concept) would be:
func listProperties(mirror: Mirror)
{
for (var i=0;i<mirror.count;i++)
{
if (mirror[i].0 == "super")
{
listProperties(mirror[i].1)
}
else
{
println(mirror[i].0)
}
}
}
To use it:
var mirror=reflect(object_instance)
listProperties(mirror)
If there is a optional property, How can I unwrap it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Could potentially clean this up by simply using a call to bridgeToObjectiveC() rather than all the individual casts to the various NS-types.