Skip to content

Instantly share code, notes, and snippets.

@jkopelioff
Created August 13, 2015 22:53
Show Gist options
  • Select an option

  • Save jkopelioff/a6100b067c96662c48f7 to your computer and use it in GitHub Desktop.

Select an option

Save jkopelioff/a6100b067c96662c48f7 to your computer and use it in GitHub Desktop.
Model Factory that maps Dictionary value to Model properties
//
// ModelFactory.swift
// Society6
//
// Created by Joel Kopelioff on 8/10/15.
// Copyright (c) 2015 Demandmedia Inc. All rights reserved.
//
import Foundation
class ModelFactory {
class func createModels<Model:BaseModel> (json:[NSDictionary], error:NSErrorPointer, modelType:Model.Type? = nil) -> [Model]
{
var objects = [Model]()
for dict in json {
if let model = ModelFactory.createModel(dict, error: error, modelType:modelType) {
objects.append(model)
}
if let error = error.memory {
break;
}
}
return objects
}
class func createModel<Model:BaseModel> (json:NSDictionary, error:NSErrorPointer, modelType:Model.Type? = nil) -> Model?
{
var object = Model()
if modelType != nil {
object = modelType!()
}
var modelAttributes = object.attributes
for attributeAndTypes in modelAttributes {
var set = false
var attribute = attributeAndTypes.0
let type:Any.Type = attributeAndTypes.1
// Internal function to set values for mapped and non-mapped attributes
func setValue(value:AnyObject?) {
if value == nil { return }
var convertedValue:AnyObject?
// Convert types
if let elementType = type as? Bool.Type where value is String {
convertedValue = value?.boolValue
} else if let elementType = type as? Float?.Type where value is String {
convertedValue = value?.floatValue
} else if let elementType = type as? Int.Type where value is String {
convertedValue = value?.integerValue
} else if let elementType = type as? String?.Type where value is String {
convertedValue = value
} else if "\(type)".match("Array") && value is Array<NSDictionary> {
let matches = "\(type)".captureUsingRegex("Array<([\\w\\.]+)>")
if matches.count > 0 && matches[0].count > 1 {
let className = matches[0][1]
let classType = NSClassFromString(className) as! BaseModel.Type
let object = classType()
// Special case
var error:NSError?
convertedValue = ModelFactory.createModels(value as! [NSDictionary], error: &error, modelType:object.dynamicType)
}
} else {
// We don't convert this type, yet
println("Attribute: \(attribute) Type: \(type) Value: \(value)")
}
if let valueToSet: AnyObject = convertedValue {
object.setValue(valueToSet, forKey: attribute)
set = true
}
}
// First check to see if attribute maps directly
if let value:AnyObject? = json.valueForKey(attribute) where value != nil {
setValue(value)
}
// Next check if we have a mapping override
if let mappings = object.mappings,
let mapArray = mappings[attribute] where Set(mappings.keys.array).contains(attribute) {
for map in mapArray {
// Take the first attribute that matches, discard the remaining
if let value:AnyObject? = json.valueForKeyPath(map) where value != nil {
setValue(value)
break
}
}
}
if !set {
NSLog("Did not set \"\(attribute)\"")
}
}
return object
}
}
@jkopelioff
Copy link
Author

Called like so...

let model = ModelFactory.createModel(jsonResult, error: &error, modelType: Post.self)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment