Выполнение NSBatchInsertRequest создает дубликаты

Когда я извлекаю сущности после пакетной вставки в контекст управляемого объекта основной очереди для обновления списка SwiftUI, я замечаю, что всегда есть дубликаты (точнее, буквальное удвоение каждой сущности).

Я выполняю пакетную вставку файлов, которые пользователь импортирует, с помощью метода «импорт файлов» в классе Manager. Затем я извлекаю их в контекст управляемого объекта основной очереди, чтобы обновить свой список SwiftUI.

class DataController {
    static let shared = DataController()

    func createNewBackgroundContext() -> NSManagedObjectContext {
        let taskContext = container.newBackgroundContext()
        taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return taskContext
    }
}

class Manager {
    func importFiles(from urls: [URL]) async {
        let importContext = DataController.shared.createNewBackgroundContext()
        
        var objects: [[String: Any]] = []
        
        for url in urls {
            if url.startAccessingSecurityScopedResource() {
                let metadata = getMetadata(url: url)
                
                let audioFileName = url.deletingPathExtension().lastPathComponent                  
                let fileExtension = url.pathExtension
                let artist = metadata?.value(forKey: "artist") as? String ?? "Unknown Artist"
                let album = metadata?.value(forKey: "album") as? String ?? "Unknown Album"
                let genre = metadata?.value(forKey: "genre") as? String ?? "Unknown Genre"
                let composer = metadata?.value(forKey: "composer") as? String ?? "Unknown Composer"
                let year = metadata?.value(forKey: "year") as? String ?? "Unknown Release Year"
                let importDate = Date()
                let artwork = audioFileName + ".\(fileExtension)"
                let trackNumber = metadata?.value(forKey: "trackNumber") as? Int ?? -1
                
                let properties: [String: Any] = [
                    "name": audioFileName,
                    "artist": artist,
                    "album": album,
                    "genre": genre,
                    "year": year,
                    "composer": composer,
                    "importDate": importDate,
                    "trackNumber": trackNumber,
                    "artwork": artwork,
                    "fileExtension": fileExtension,
                    "favourite": false
                ]
                objects.append(properties)

                //Save the file to disk
                save(url: url, with: audioFileName + ".\(fileExtension)")
            }
            
            url.stopAccessingSecurityScopedResource()
        }
             
//objects array is confirmed to have the right number of items to be inserted

await importContext.perform { [weak self] in
        guard let self else { return }
                    
    let batchInsertRequest = NSBatchInsertRequest(entity: AudioFile.entity(), objects: objects)
    batchInsertRequest.resultType = .objectIDs
    
    let result = try? importContext.execute(batchInsertRequest) as? NSBatchInsertResult
    let objs = result?.result as? [NSManagedObjectID] ?? []

//The number of ids is always double here for some reason...

    let changes: [AnyHashable: Any] = [NSInsertedObjectIDsKey: objs]
    // Merge changes
    NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [moc])
}

        await MainActor.run {
             SongsListViewModel.shared.fetchAudioFiles()
        }
    }
}

class SongsListViewModel: ObservableObject {
    static let shared = AllSongsListViewModel()
    
    @Published var audioFiles = [AudioFile]()
    private let moc = DataController.shared.container.viewContext
    
    func fetchAudioFiles() {
        let fetchRequest = AudioFile.fetchRequest()
        if let audioFiles = try? moc.fetch(fetchRequest) {
            self.audioFiles = audioFiles
        }
    }
}

Какие действия по устранению неполадок вы здесь выполнили: у вас есть повторяющиеся записи, но проверили ли вы, есть ли у вас повторяющиеся файлы, добавили ли вы какие-либо операторы печати в свой код, чтобы следить за ходом выполнения и т. д... Воспроизвести это практически невозможно для кто-нибудь еще, поэтому нам нужна вся имеющаяся у вас информация.

Joakim Danielson 30.05.2024 17:28

Дубликаты файлов не записывались. Также не было создано дубликатов объектов для вставки в пакетный запрос. Я предполагаю, что это из-за проблем с контекстом нескольких объектов, поскольку существует как основной, так и частный контекст?

SwiftUIEnthusiast 30.05.2024 17:38

Кроме того, дубликаты возникают только после того, как я немедленно извлекаю аудиофайлы. Когда я закрываю приложение и загружаю аудиофайлы, дубликатов нет.

SwiftUIEnthusiast 30.05.2024 19:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел источник повторяющихся записей. Если кто-нибудь захочет объяснить, почему для параметра «shouldMigrateStoreAutomatically» должно быть установлено значение true, чтобы предотвратить вставку NSBatchInsertRequest копии для каждого объекта, это было бы здорово.

let description = NSPersistentStoreDescription()
//I have set this property of the description to false all along. Apparently this must be set to true to avoid duplicates when performing a NSBatchInsertRequest
//description.shouldMigrateStoreAutomatically = false
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]

Не было никакой информации об этом при переполнении стека или каких-либо упоминаний об этом в документации Apple.

Другие вопросы по теме