Reputation: 1289
I'm currently implementing an insert-or-update pattern with Realm by calling realm.create(T.self, value: object, update: true)
. object
is JSON returned from a rest call and it may contain some or all of the properties associated with that realm object. (In other words, I need to support partial updates.)
In many of the JSON objects there is a key called description
. Since I cannot have a Realm object subclass with a property called public dynamic var description
I need to choose another name and make sure it is mapped properly when calling realm.create
. I know what you are thinking, I can just do the mapping before calling create. However, the JSON may also have nested objects / array of objects and it seems redundant for me to setup mappings for all nested properties as well, when Realm already knows where those objects map to. It would be much cleaner if I could simply define a mapping in each Object
subclass and then Realm could figure out the rest.
My first attempt at solving this was to override the init
functions for Object
(even though comments explicitly say not to, had to try) and that did not work because none of the init methods that take in a JSON object were actually called with using realm.create
.
Is there any way to make my life easier here?
Note: I am using Swift 2.0 and the swift-2.0
branch of Realm
Upvotes: 2
Views: 4595
Reputation: 2014
You can use also SwiftyJSONModel. The realm Model will look something like this:
final class Person: Object {
dynamic var name = ""
dynamic var age = ""
dynamic var isMarried = false
}
extension Person: JSONObjectInitializable {
enum PropertyKey: String {
case name, age, isMarried
}
convenience init(object: JSONObject<PropertyKey>) throws {
self.init()
name = try object.value(for: .name)
age = try object.value(for: .age)
isMarried = try object.value(for: .isMarried)
}
}
This framework has some nice features, like:
String
or Int
JSON
was invalid. This really saves a lot of timeJSON
Upvotes: 1
Reputation: 4918
Realm still doesn't support proper mapping when using Swift, so let me elaborate on jpsim comment.
ObjectMapper provides a powerful mapping mechanism which not only let you choose your model properties names, but also handle nicely any sanitization you might need during the mapping process.
Here is an example I've written for a dummy project :
import ObjectMapper
class Color: RLMObject, Mappable{
dynamic var myId = 0
dynamic var myTitle = ""
dynamic var username = ""
dynamic var hex = ""
override static func primaryKey() -> String?{
return "id"
}
required convenience init?(_ map: Map){
self.init()
}
static func mappedColor(dict:Dictionary<String, AnyObject>) -> Color{
return Mapper<Color>().map(dict)! as Color
}
func mapping(map: Map) {
id <- map["id"]
title <- map["title"]
username <- map["userName"]
hex <- map["hex"]
}
}
You can see I have both a mapping
function linked to the ObjectMapper Mappable
protocol, as well as a mappedColor
function which is nothing more than a convenient way to map a JSON to retrieve my model object.
I can then use it within a webservice call response likeso :
[...]
if let JSON:Array = response.result.value as? Array<[String: AnyObject]> {
do{
try RLMRealm.defaultRealm().transactionWithBlock {
for dict in JSON{
let color = Color.mappedColor(dict)
RLMRealm.defaultRealm().addOrUpdateObject(color)
}
}
} catch let error as NSError {
print(error)
}
}
[...]
Upvotes: 3
Reputation: 14409
Realm doesn't have any built-in keypath/value mapping mechanisms, so whatever you pass to Object(value:)
needs to match that model's schema exactly. Just like KVC.
Whatever you do, you'll need to sanitize (e.g. map keys, transform values, fold/unfold objects) before passing those values into Realm. You can either do this yourself by recursively walking your dictionary/array obtained from JSON, or by using a library like ObjectMapper, which aims to simplify this kind of work. Here's one ObjectMapper & Realm user's way of using both tools together.
It's worth noting that Realm does intend to eventually support this kind of key mapping in the future (tracked as #694), but work on that hasn't yet begun.
Upvotes: 0