Skip to content

Instantly share code, notes, and snippets.

@mchambers
Created June 25, 2014 07:49
Show Gist options
  • Save mchambers/67640d9c3e2bcffbb1e2 to your computer and use it in GitHub Desktop.
Save mchambers/67640d9c3e2bcffbb1e2 to your computer and use it in GitHub Desktop.
A simple, limited model-to-JSON serializer in Swift.
// 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)
@mchambers
Copy link
Author

Could potentially clean this up by simply using a call to bridgeToObjectiveC() rather than all the individual casts to the various NS-types.

@qadram
Copy link

qadram commented Jul 4, 2014

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)

@mqshen
Copy link

mqshen commented Dec 8, 2014

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