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
Can Nscoding and Codable Co-Exist
Passing Arguments to #Selector Method in Swift
iOS 12 Errors: Appears to Be from a Different Nsmanagedobjectmodel Than This Context'S
Cannot Preview in This File -- Message Send Failure
How to Convert Tuple to Anyobject in Swift
Swiftui: Update Navigationview After Deletion (Ipad)
Subclass Uiscrollview in Swift for Touches Began & Touches Moved
Combining Custom Property Wrapper with @Published
How to Convert Text to Speech for Osx in Swift Playground
iOS Charts Remove Decimal from Yvalues
A Swiftier Way to Convert String to Unsafepointer<Xmlchar> in Swift 3 (Libxml2)
Realm: Map JSON to Realm-Objects with Alamofire
Swift Protocol with Associated Type - Type May Not Reference Itself as a Requirement
New Fuitableviewdatasource - How to Use? Swift 3
Urlsessiondelegate's Didwritedata Not Call When App Is Going to Background in iOS12