Florian L.
Florian L.

Reputation: 849

Local migration with List<String> in swift

With Realm 5.4.0 I'm trying to migrate:

public final class MyObject: Object {
   public let tags = List<String>()
}

to

public final class MyObject: Object {
   public let tagIds = List<String>()
}

Therefore I wanted to write a migration block like this:

migration.enumerateObjects(ofType: "MyObject") { oldObject, newObject in
   let tags = [String: String]() // filled earlier
   let oldTagList = oldObject!.dynamicList("tags")
   let newTagList = newObject!.dynamicList("tagIds")

   oldTagList.forEach { tag in
      if let id = tags[tag as String] { // this does not compile (1)
         newTagList.append(id) // this does not work (2)
      }
   }
}

From the oldTagList I get DynamicObjects which cannot be casted to strings (1). I was able to solve this problem by a very ugly workaround:

let oldTagList = unsafeBitCast(oldObject!["tags"] as! List<DynamicObject>, to: List<String>.self)

What I was not able to solve is to add the id string to newObjects tagIds list (2).

I tried to cast the list the same way than oldObjects tags list but that throws an EXC_BAD_ACCESS error.

How can I migrate / convert the content of a List<String> into another List<String>?

Upvotes: 2

Views: 459

Answers (1)

Jay
Jay

Reputation: 35657

The objective in the question is to create a new tag List for the updated objects with different tags based on a dictionary lookup. Let me set this up for clarity

Here's the existing object with a tag List (of strings)

object_0
   tags = ["a", "b", "c"]

and the new object will look like this

object_0
   tagIds = ["tag_a", "tag_b", "tag_c"]

the lookup is done through an existing dictionary that would look like this

tags ["a": "tag_a",
      "b": "tag_b",
      "c": "tag_c"]

So a maps to tag_a, b maps to tag_b etc

Here's the migration block to do that

migration.enumerateObjects(ofType: MyObject.className()) { oldItem, newItem in
    let oldTags = oldItem!["tags"] as! List<MigrationObject>
    let tagCount = oldTags.count
    
    let updatedList = List<String>()
    
    for index in 0..<tagCount {
        let oldTag = oldTags[index]
        let val = "\(oldTag)" //make the NSTaggedPointerString a String
        //let val = oldTag.description this may work as well
        
        if let updatedTag = self.tags[val] {
            updatedList.append(updatedTag)
        }
    }
    
    newItem!["tagIds"] = updatedList
 }

Upvotes: 2

Related Questions