Realm: Map JSON to Realm-Objects with Alamofire

Realm: Map JSON to Realm-Objects with Alamofire

Realm offers built-in limited capabilities of mapping arbitrary JSON structures to RLMObjects. But there are some good third-party libraries, which could assist you with your use-case. You might want to checkout these:

  • Realm-JSON (Objective-C), which offers a declarative, Mantle like way of defining your mapping
  • ObjectMapper (Swift), which offers Realm and Alamofire support

Alamofire, Objectmapper, Realm: Nested Objects

The old ListTransform solution no longer works in Swift 3.

This is what I'm using now; put this in a file called, ListExtensions.swift, for example.

import Foundation
import ObjectMapper
import RealmSwift

/// Maps object of Realm's List type
func <- <T: Mappable>(left: List<T>, right: Map)
{
var array: [T]?

if right.mappingType == .toJSON {
array = Array(left)
}

array <- right

if right.mappingType == .fromJSON {
if let theArray = array {
left.append(objectsIn: theArray)
}
}
}

This allows you to simply use it like this:

class Parent: Object, Mappable {
dynamic var id: Int = 0
var children = List<Child>()

required convenience init?(_ map: Map) {
self.init()
}

func mapping(map: Map) {
id <- map["id"]
children <- map["children"]
}
}

Mapping Nested JSON Realm object in swift

Try to make model like this

import Foundation
import RealmSwift

class Name: Object {
dynamic var id = 0
dynamic var fisrtname : String?
dynamic var lastname : String?
dynamic var Address : UserAddress? = UserAddress()

override static func primaryKey() -> String? {
return "id"
}
}

class UserAddress: Object {

dynamic var id = 0
dynamic var city : String?
dynamic var phone : String?
dynamic var street : String?

override static func primaryKey() -> String? {
return "Id"
}
}

And To get address from Json :

let responseResult = result["Result"] as! NSDictionary
let name = Name(value: responseResult)
let address = name.Address?.city

Cannot map JSON objects to Realm

For the second part of your question, regarding the migration error. You're getting the error because you've changed your object definitions and they no longer match what's stored in the Realm database. You will need to handle cleanly migrating from one version to the next. Or, if your data is just cached server data, and doesn't need to be persisted for the user since it can be recreated, (or you're in Debug/Testing mode), you can add this to your AppDelegate (at the top of didFinishLaunchingWithOptions... before you do anything with Realm):

    // Auto wipe Realm store if schema has changed
do {
let _ = try Realm()
}
catch {
DataController.deleteRealmFilesAtPath(Realm.Configuration.defaultConfiguration.fileURL!)
}

And then, in your DataController class, include this static method:

static func deleteRealmFilesAtPath(fileURL: NSURL) {
guard let path = fileURL.path else { return }
let fileManager = NSFileManager.defaultManager()
guard fileManager.fileExistsAtPath(path) else { return }

do {
try fileManager.removeItemAtPath(path)
try fileManager.removeItemAtPath(path + ".lock")
try fileManager.removeItemAtPath(path + ".note")
}
catch {
print("Unable to delete Realm files: \(error)")
}
}

This will wipe the old database files on app launch if the schema has changed. Of course, you'll lose any data in there as well, so you can only use this in some cases.

ObjectMapper + Realm + Alamofire

I finally figured it out and it works very well. I compute the difference of the cached data and the new data and delete it:

private func deleteOrphans(existingData: List<VotingHeader>, fetchedData:[VotingHeader]){

guard existingData.count>0 else {
return
}

let existingIDs = Set(existingData.map({$0.votingID}))
let incomingIDs = fetchedData.map({$0.votingID})
let idsToDelete = existingIDs.subtract(incomingIDs)

if idsToDelete.count>0{
let itemsToDelete = self.realm.objects(VotingHeader).filter("votingID IN %@",idsToDelete)

try! self.realm.write{
self.realm.delete(itemsToDelete)
}
}
}

How should I assign my data models to map the JSON using Alamofire?

Add a method to convert from FriendModel to UserModel:

struct UserModel {
init(friend: FriendModel) {
id = friend.id
userFirstName = friend.firstName
userSurname = friend.lastName
... // assign all the other fields as needed
}
}

Then use it to convert your results:

friendsAPI.getFriends { [weak self] apiFriends in
self?.friends0 = apiFriends.map({ UserModel(friend: $0) })
}

Here it is an init method, but feel free to put it in a normal func like func userFromFriend(_ friend: FriendModel) -> UserModel, and put that func wherever you want.



Related Topics



Leave a reply



Submit