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
Simple Clickable Link in Cocoa and Swift
Input Type=File Not Working in Webview of Os X Application
Swift - Get Nsbundle for Test Target
Core Data: Could Not Cast Value of Type 'Mytype_Mytype_2' to Mytype
Show Folder's Contents in Finder Using Swift
Use a Function to Find Common Elements in Two Sequences in Swift
How Are Optional Values Implemented in Swift
Swift Standard Documentation Comment
How to Instantiate a Storyboard from a File Within an iOS Playground
Detailed Instruction on Use of Nsopenpanel
Using Swift to Disable Sleep/Screen Saver for Osx