Alamofire, Objectmapper, Realm: Nested Objects

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"]
}
}

How to post nested json by objectMapper and Alamofire?

Based on the request structure, below is the simplified way to encode/decode ChartsReqModel object,

class  ChartsReqModel: NSObject, Mappable {
var TokenId:String?
var ObjSearch: ChartObjSearchReqModel?

required init?(map: Map) {}

func mapping(map: Map) {
self.TokenId <- map["TokenId"]
self.ObjSearch <- map["ObjSearch"]
}
}

Now when you have json from the response, you can decode ChartsReqModel object by passing that json as below,

let chartsObject = ChartsReqModel(JSON: jsonFromResponse)

And when you want to post the ChartsReqModel json, you can encode it as below

let paramsJson = chartsObject.toJSON()

Does realm need nested objects to be added explicitly

This is sufficient

realm.write{
let dog = Animal(name: "Daisy")
let person = Person(name: "John Wick", pet: dog)

realm.add(person) // <----- This

}

The Animal object will be inserted automatically , just make a query for that model and you will get it

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

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)
}
}
}

Count Occurrences of Nested Objects w/ Realm Swift

One of the possible solutions is to rely on Realm's built in functionality and use an inverse relationship.

Just add the inverse relationship to your Actor model class. actedIn will contain a reference to all Movie objects, which contain the Actor instance in their actors property.

When looking for the actor with most movies, you just have to fetch all actors from your Realm, then use the built in max(by:) function to find the one, whose actedIn has the most elements.

@objcMembers class Actor: Object {
dynamic var name = ""
let actedIn = LinkingObjects(fromType: Movie.self, property: "actors")
}

@objcMembers class Movie: Object {
dynamic var _id: String? = nil
dynamic var actors = List<Actor>()

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

//Generate test data
try! realm.write {
let nicholasCage = Actor(value:["name":"Nicholas Cage"])
let adamSandler = Actor(value:["name":"Adam Sandler"])
let jessicaBiel = Actor(value:["name":"Jessica Biel"])
let nicoleKidman = Actor(value:["name":"Nicole Kidman"])
realm.add([nicholasCage,adamSandler,jessicaBiel,nicoleKidman])
let firstMovie = Movie()
firstMovie.actors.append(objectsIn: [nicholasCage,nicoleKidman])
firstMovie._id = "first"
let secondMovie = Movie()
secondMovie.actors.append(objectsIn: [nicholasCage,adamSandler])
secondMovie._id = "second"
let thirdMovie = Movie()
thirdMovie.actors.append(objectsIn: [nicholasCage,nicoleKidman,jessicaBiel])
thirdMovie._id = "third"
realm.add([firstMovie,secondMovie,thirdMovie])
}

let allActors = realm.objects(Actor.self)
let actorWithMostMovies = allActors.max(by: {$0.actedIn.count < $1.actedIn.count})
actorWithMostMovies?.name //"Nicholas Cage"
actorWithMostMovies?.actedIn.count //3

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

Using Alamofire and Objectmapper the integer value always zero

Does the "id" field exist in the JSON file? If it does not, your initial value of zero will remain. Is the value in quotes in the JSON file? If it is, then it's a string. I don't know if ObjectMapper will convert it to Int.

Moved my comment to an answer.



Related Topics



Leave a reply



Submit