thatjuan thatjuan - 3 months ago 56
Swift Question

How to validate values before creating Realm object (in RealmSwift)

My application code gets JSON data from a server, converts it to a Dictionary and then uses that to hydrate and attempt to save a RealmSwift object with a matching schema.

I ran into a crash caused by a

Float
value coming into a field that was declared as
Int
in the model.
RLMException
was thrown.

As suggested in this thread, one doesn't simply try to catch
RLMException
.

My question is, is that answer correct? And, if so, what is the correct way to prevent a crash when an unexpected value is found? Isn't there some sort of validation mechanism that I can run on all of the values before attempting to set them?

Answer

I ended up writing an extension to handle this. At the moment I'm only validating numbers and dates, but the switch statement could check every single property type easily.

extension Object {

    public convenience init( withDictionary rawData: [String:AnyObject] ) {

        var sanitizedData = rawData

        let dynamicSelf = self.dynamicType

        let schema = dynamicSelf.sharedSchema()


        for property in schema.properties {

            guard let value = sanitizedData[property.name] else { continue }

            var isValid = true

            switch property.type {

                case .Double:

                    let val = Double(String(value))

                    if val == nil || val!.isNaN {
                        isValid = false
                    }

                case .Float:

                    let val = Float(String(value))

                    if val == nil || val!.isNaN {
                        isValid = false
                    }

                case .Int:

                    if Int(String(value)) == nil {
                        isValid = false
                    }

                case .Date:

                    if Int64(String(value)) == nil {

                        isValid = false

                    } else {

                        sanitizedData[property.name] = NSDate(timeIntervalSince1970: value.doubleValue / 1000)

                    }

                default:
                    break

            }


            if !isValid {

                log.error( "Found invalid value: \(value) for property \(property.name) of \(dynamicSelf)" )

                sanitizedData.removeValueForKey(property.name)

            }

        }

        self.init( value: sanitizedData )

    }

}