Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access list property in Realm migration #6393

Open
EmDee opened this issue Jan 7, 2020 · 2 comments
Open

Access list property in Realm migration #6393

EmDee opened this issue Jan 7, 2020 · 2 comments

Comments

@EmDee
Copy link

EmDee commented Jan 7, 2020

Goals

I've added a primary key to an object that didn't have one before, which is based on some of the object's property, one of which has a List<String> data type. However, I am not able to correctly access the list property, hence I can't write the migration for the new primary key.

Expected Results

Being able to parse the elements in the List property.

Actual Results

Not being able to parse the list.

Code Sample

My database object looks as follows:

@objcMembers
public class TestObject: Object {
    dynamic private(set) var id: String = ""

    let _foobar: List<String> = .init()

    private(set) public var foobar: [SomeEnum] {
        set {
            _foobar.removeAll()
            _foobar.append(objectsIn: newValue.map { $0.rawValue })
        }

        get {
            return _foobar.compactMap { SomeEnum(rawValue: $0) }
        }
    }

    public override class func primaryKey() -> String? {
        return "id"
    }

    convenience init(foo: [SomeEnum]) {
        self.init()

        let foobar = foo.reduce("", { $0 + "-" + $1.rawValue })

        self.id = foobar
        self.foobar = foo
    }
}

In my migration block I'm trying to access _foobar, but can't seem to get it right:

static func migratePrimaryKey(_ migration: RealmSwift.Migration) {
    migration.enumerateObjects(ofType: TestObject.className()) { old, _ in
        let field: String = "_foobar"

        let test1 = old?[field] as? List<String>
        let test2 = old?[field] as? [String]
        let test3 = old?[field] as? List<DynamicObject>
        let test4 = old?[field]
    }
}

Both test and test2 are nil. test3 throws some exceptions:

Could not cast value of type 'NSTaggedPointerString' (0x7fff87a8a270) to 'RealmSwift.DynamicObject' (0x10f065fe8).

The output of test4 shows the following:

(lldb) po test4
 Optional<Any>
  - some : List<string> <0x600001fb5f80> (
    [0] someContent
)

There seems to be some technical restriction which prevents me from accessing the actual list properties of my migration object?

Version of Realm and Tooling

Realm framework version:

Realm Object Server version: 3.19.0

Xcode version: 11.2.

iOS/OSX version: 13.2

Dependency manager + version: Carthage 0.34.0

@EmDee
Copy link
Author

EmDee commented Jan 7, 2020

If my property doesn't contain String, but a custom object instead, I know I can do something along the lines of:

@objcMembers
public class CustomObject: Object {
    dynamic var foo: Int = 0
}

migration.enumerateObjects(ofType: TestObject.className()) { old, new in
    guard let old = old, let new = new else { return }

    let customObjects = old.dynamicList("_foobar")

    for obj in customObjects {
        if let foo = obj["foo"] as? Int {
            print(foo)
        }
    }
}

Are primitive data type handled differently in Realm? If so a workaround would be to have a object wrapping the String, but that seems rather wrong.

@tgoyne tgoyne added the T-Bug label Jan 15, 2020
@tgoyne tgoyne self-assigned this Jan 15, 2020
@tgoyne
Copy link
Member

tgoyne commented Jan 15, 2020

unsafeBitCast(old![field] as! List<DynamicObject>, to: List<String>.self) will give you a List<String> from the migration object's field. Making this more reasonable is a breaking change for anything currently using that, so I guess it'll have to go into 5.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants