SwiftData Custom Migration with no change in schema?

I'll preface by saying I'm a new Swift developer, having a go at my first app. Just a simple memory tracker.

I'm building it using SwiftData + iCloud Syncing. I had set up my model like this:

@Model
final class Memory {
    var content: String = ""
    var dateCreated: Date = Date.now
    var dateUpdated: Date = Date.now
    var tags: [Tag]? = [Tag]()
    @Attribute(.externalStorage) var images: [Data] = [Data]()
    
    init(
        content: String = "",
        dateCreated: Date = .now,
        dateUpdated: Date = .now,
        tags: [Tag] = [Tag](),
        images: [Data] = [Data]()
    ) {
        self.content = content
        self.dateCreated = dateCreated
        self.dateUpdated = dateUpdated
        self.tags = tags
        self.images = images
    }
}

But I discovered that led to a massive performance issue as soon as someone added a few images to a Memory. Maybe SwiftData isn't correctly putting an ARRAY of Data into external storage? My memory usage would just balloon with each photo added. All the examples I've seen just use a singular Data type for external storage, so not sure.

Anyway, I played around with different options and figured out that a new MemoryPhoto struct was probably best, so I put the old model in a V1 schema and my NEW V2 model looks like this...

enum DataSchemaV2: VersionedSchema {
    static var versionIdentifier = Schema.Version(2, 0, 0)
    
    static var models: [any PersistentModel.Type] {
        [Memory.self, Tag.self, MemoryPhoto.self]
    }
    
    @Model
    final class Memory {
        var content: String = ""
        var dateCreated: Date = Date.now
        var dateUpdated: Date = Date.now
        var tags: [Tag]? = [Tag]()
        @Relationship(deleteRule: .cascade) var photos: [MemoryPhoto]? = [MemoryPhoto]()
        @Attribute(.externalStorage) var images: [Data] = [Data]()
        
        init(
            content: String = "",
            dateCreated: Date = .now,
            dateUpdated: Date = .now,
            tags: [Tag] = [Tag](),
            images: [Data] = [Data](),
            photos: [MemoryPhoto] = [MemoryPhoto]()
        ) {
            self.content = content
            self.dateCreated = dateCreated
            self.dateUpdated = dateUpdated
            self.tags = tags
            self.images = images
            self.photos = photos
        }
    }

    @Model
    final class MemoryPhoto {
        @Attribute(.externalStorage) var originalData: Data?
        @Relationship(inverse: \Memory.photos) var memory: Memory?
        
        init(originalData: Data? = nil, memory: Memory? = nil) {
            self.originalData = originalData
            self.memory = memory
        }
    }

Here's my migration, currently, which does work, because as best I can tell this is a lightweight migration...

enum DataMigrationPlan: SchemaMigrationPlan {
    
    static var schemas: [any VersionedSchema.Type] {
        [DataSchemaV1.self, DataSchemaV2.self]
    }
    
    static var stages: [MigrationStage] {
        [migrateV1toV2]
    }
    
    static let migrateV1toV2 = MigrationStage.lightweight(fromVersion: DataSchemaV1.self, toVersion: DataSchemaV2.self)

}

But what I'm trying to figure out now is to migrate the former memory.images of type [Data] to the new memory.photos of type [MemoryPhoto], and been struggling. Any type of custom migration I do fails, sometimes inconsistently. I can try to get the exact errors if helpful but at this point not even a simple fetch to existing memories and updating their content as a part of the migration works.

Is there a way to write a hypothetical V2 to V3 migration that just takes the images and puts them in the photos "slot"? For instance, what I do have working is this function that basically runs a "migration" or sorts when a given memory appears and it has the former images property.

....
        .onAppear {
            convertImagesToPhotos()
        }
    }
    
    private func convertImagesToPhotos() {
        guard !memory.images.isEmpty && memory.unwrappedPhotos.isEmpty else { return }
        
        let convertedPhotos = memory.images.map { imageData in
            MemoryPhoto(originalData: imageData)
        }
        memory.photos?.append(contentsOf: convertedPhotos)
        
        memory.images.removeAll()
    }

Any help or pointers appreciated for this newbie swift developer. If helpful, here's the main App struct too...

@main
struct YesterdaysApp: App {
    @Environment(\.scenePhase) var scenePhase
    @AppStorage("writingRemindersEnabled") var writingRemindersEnabled: Bool = false
    let container: ModelContainer
    
    init() {
        do {
            container = try ModelContainer(
                for: Memory.self,
                migrationPlan: DataMigrationPlan.self
            )
        } catch {
            fatalError("Failed to initialize model container.")
        }
    }
    
    var body: some Scene {
        WindowGroup {
            OuterMemoryListView()
                .yesterdaysPremium()
        }
        .modelContainer(container)
    }
}
SwiftData Custom Migration with no change in schema?
 
 
Q