RustamG
RustamG

Reputation: 1825

Instantiate realm object with an old schema inside migration block

I've added a calculation property to a realm object and now I'm stuck on setting the value to it inside a migration block because I cannot instantiate an object to pass it to the calculator.

Here is my model:

import Foundation
import RealmSwift

class Loan: Object {

    dynamic var id: String = NSUUID().UUIDString
    dynamic var creationDate: NSDate = NSDate()
    dynamic var title: String = ""
    dynamic var amount: Double = 0.0
    dynamic var rate: Float = 0.0
    dynamic var term: Int = 0
    dynamic var type: Int = TYPE_ANNUITY
    dynamic var firstPaymentDate: NSDate = NSDate()
    dynamic var issueDate: NSDate?

    let extras = List<Extra>() // this is a list of nested realm models which is also used for calculation

    dynamic var calculation: CalculationResult? // !! added this property !!

    static let TYPE_ANNUITY = 0
    static let TYPE_GRADED = 1


    override class func primaryKey() -> String? {
        return LoanPropNames.Id
    }
}

struct LoanPropNames {
    static let CreationDate = "creationDate"
    static let Id = "id"
    static let Calculation = "calculation"
}

The value for the calculation is calculated by a helper method with signature like this:

func calculate(loan: Loan) -> CalculationResult

Here is the code for configuration for the Realm:

class RealmConfigurator {

    private static let schemaVersionAddedCalculationProp: UInt64 = 1

    private static let schemaVersionLatest = schemaVersionAddedCalculationProp

    static func createConfiguration() -> Realm.Configuration {

        return Realm.Configuration(
            schemaVersion: schemaVersionLatest,
            migrationBlock: {
                migration, oldSchemaVersion in

                if oldSchemaVersion < schemaVersionAddedCalculationProp {

                    migration.enumerate(Loan.className()) {
                        oldObject, newObject in

                        if let oldObject = oldObject,
                            let newObject = newObject {

                            // this is how I try to instantiate a loan to pass it to the CalculationHelper
                            let loan = Loan(value: oldObject, schema: migration.oldSchema)

                            newObject[LoanPropNames.Calculation] = CalculationHelper.calculate(loan)
                        }    
                    }
                }
            }
        )
    }
}

The problem is in the line

let loan = Loan(value: oldObject, schema: migration.oldSchema)

The compiler says

Cannot convert value of type 'Schema' to expected argument type 'RLMSchema'

If I try to run it like this: let loan = Loan(value: oldObject)

I get runtime error:

Terminating app due to uncaught exception 'RLMException', reason: 'Invalid property name calculation for class Loan.'

Question: How can I instantiate a Loan object during migration in order to fill the calculation property?

I do not want to make it lazy because it needs to be recalculated when other properties are changed. Also making it a computed property is not a good solution because it takes a while to compute the value with each access.

Upvotes: 0

Views: 1008

Answers (1)

kishikawa katsumi
kishikawa katsumi

Reputation: 10573

I think that you can use KVC to fill loan object's properties. Like the following:

// 1. Create empty loan object
let loan = Loan()

// 2. Fill loan object's properties with old object
let propertyNames = oldObject.objectSchema.properties.map { $0.name }
let values = oldObject.dictionaryWithValuesForKeys(propertyNames)
loan.setValuesForKeysWithDictionary(values)

// 3. Create standalone calcuration object
let calculation = CalculationHelper.calculate(loan)

// 4. Save calculation object and assign
newObject[LoanPropNames.Calculation] = migration.create(CalculationResult.className(), value: calculation)

Upvotes: 1

Related Questions