Well after a lot of tests I found a way to reduce the time to only 1-2 seconds of data creation to insert and 7-9 seconds of insertion (it can be lowered more if less records are shown, for example if I show when 1000 inserts is reduced to 4-6 seconds).
The first thing I have to say, is that the objects were wrong, although in sqlite many-to-many relationships are made with an auxiliary table, here it is completely redundant, since one can insert the same record several times in a array, so the objects are like this:
class ProductRealm: Object {
public dynamic var id: String = ""
public dynamic var code: String = ""
public dynamic var detail: String = ""
public dynamic var onHand: Int = 0
public dynamic var price: Double = 0
public dynamic var isSerialized: Int = 0
public dynamic var isLotNumber: Int = 0
override static func primaryKey() -> String? {
return "id"
}
}
class GroupRealm: Object {
public dynamic var id = 1
public dynamic var name = ""
public dynamic var update = Date()
let products = List<ProductRealm>()
override static func primaryKey() -> String? {
return "id"
}
}
This means that unlike sqlite it is only necessary to insert the data in a single "table" and the references in the other "table" which makes it much simpler and improves the performance a little, however the Insertion times were still very high.
After many tests it occurred to me to use the jsonObject to insert, since the idea is to bring these records from a server, and to my surprise this greatly reduced the insertion time compared to the dictionaries, so the code final would look like this:
//
// ViewController.swift
// TestRealm
//
// Created by Sergio Castro on 10/02/17.
// Copyright © 2017 BasTechSoluctions. All rights reserved.
//
import UIKit
import RealmSwift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Mostrar la ubicación del proyecto para ubicar la base de datos
print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.absoluteString)
DispatchQueue(label: "background").async { //Abrir un nuevo hilo para insertar de forma asíncrona
autoreleasepool {
let date1 = Date() // Inicia el conteo del tiempo
let realm = try! Realm() // Instanciar realm en el hilo nuevo
let products = realm.objects(ProductRealm.self) //Crear una lista de todos los productos
//Crear grupo
let group = GroupRealm()
group.id = 1
group.name = "test"
try! realm.write { //Insertar/Reemplazar grupo, sin productos
realm.create(GroupRealm.self, value: group, update: true)
}
///Crear json
//Primero creo un String, donde ingreso todos los datos en formato [{},{},...]
var stringJson = "["
for i in 0..<30000 {
if(i > 0){ stringJson.append(",") }
let dataOrigin = "{\"id\": \"\(i)\", \"code\": \"\", \"detail\": \"\", \"onHand\": 0, \"price\": 0, \"isSerialized\": 0, \"isLotNumber\": 0}"
stringJson.append("\(dataOrigin)")
}
stringJson.append("]")
//Convertir el String en Datos y luego pasarlo a jsonObject (esto para simular el proceso de descarga de datos)
let data = stringJson.data(using: .utf8)!
let jsonP = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [Any]
//Mostrar el tiempo empleado para la creación del json en consola, el tiempo está en segundos por defecto
let date2 = Date()
var time = date2.timeIntervalSince(date1)
print("Json creation in seconds \(time)")
//Recorrer el json en grupos de 100, tantas veces haga falta para recorrer por completo el json, en este caso 300 veces
let limit = 100
for c in 0..<(jsonP.count / limit){
//Insertar/Reemplazar los grupos de datos
realm.beginWrite()
for i in 0..<limit{
let row = jsonP[i + (c*limit)]
realm.create(ProductRealm.self, value: row, update: true)
}
try! realm.commitWrite()
//Mostrar en consola la cantidad de procesos realizados vs la cantidad de registros actuales
print("\((c+1)*limit) / \(products.count)")
}
group.products.append(objectsIn: products) //Agregar los productos al grupo, aquí se pueden poner filtros
//Actualizar el grupo, para que el array products tenga una referencia a sus productos correspondientes
try! realm.write {
realm.create(GroupRealm.self, value: group, update: true)
}
// Calcular el tiempo de inserción y mostrarlo en consola
let date3 = Date()
time = date3.timeIntervalSince(date2)
print("Insert time in seconds \(time)")
// Calcular el tiempo total del calculo
time = date3.timeIntervalSince(date1)
print("total time in seconds \(time)")
}
}
}
}
class ProductRealm: Object {
public dynamic var id: String = ""
public dynamic var code: String = ""
public dynamic var detail: String = ""
public dynamic var onHand: Int = 0
public dynamic var price: Double = 0
public dynamic var isSerialized: Int = 0
public dynamic var isLotNumber: Int = 0
override static func primaryKey() -> String? {
return "id"
}
}
class GroupRealm: Object {
public dynamic var id = 1
public dynamic var name = ""
public dynamic var update = Date()
let products = List<ProductRealm>()
override static func primaryKey() -> String? {
return "id"
}
}
Well, I'll leave it that way, but if you find a way to optimize it, I'd really appreciate it.