SwiftUI и функции — Не удается найти «viewContext» в области видимости

#ios #swift #function #core-data #swiftui

Вопрос:

Я хочу отделить свои функции от представлений SwiftUI. У меня есть эта функция:

 import Foundation
import CoreData

func deleteAll() {
    let fetchRequestItems: NSFetchRequest<NSFetchRequestResult> = Item.fetchRequest()
    let deleteRequestItems = NSBatchDeleteRequest(fetchRequest: fetchRequestItems)
    
    do {
        try viewContext.save()
        try viewContext.execute(deleteRequestItems)
        viewContext.reset()
    } catch let error as NSError {
        print(error)
    }
}
 

Я получаю ошибку в 3 строках с viewContext:

Не удается найти «viewContext» в области видимости

Та же функция работает, когда она находится внутри представления SwiftUI. Но в представлениях есть viewContext, введенный таким образом:

 ContentView()
.environment(.managedObjectContext, persistenceController.container.viewContext)
 

Итак, вопрос в том,:
Как внедрить/использовать контекст основных данных (viewContext) внутри функций в отдельных файлах Swift?

РЕДАКТИРОВАТЬ: Persistence.swift взят из шаблона SwiftUI 2.0 и выглядит так:

 import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    static var preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        for _ in 0..<10 {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()
        }
        
        do {
            try viewContext.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nsError = error as NSError
            fatalError("Unresolved error (nsError), (nsError.userInfo)")
        }
        return result
    }()

    let container: NSPersistentCloudKitContainer

    init(inMemory: Bool = false) {
        container = NSPersistentCloudKitContainer(name: "Moneto")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                Typical reasons for an error here include:
                * The parent directory does not exist, cannot be created, or disallows writing.
                * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                * The device is out of space.
                * The store could not be migrated to the current model version.
                Check the error message to determine what the actual problem was.
                */
                fatalError("Unresolved error (error), (error.userInfo)")
            }
        })
    }
}
 

Комментарии:

1. deleteAll(context: NSManagedObjectContext) { … }

2. Это работает! Спасибо, @JoakimDanielson 🙂 Не могли бы вы отправить его в качестве ответа, пожалуйста, чтобы я мог его принять? 2 небольших комментария. 1. Это deleteAll(viewContext: NSManagedObjectContext) { … } в моем случае. 2. Когда я запускаю функцию, я должен использовать deleteAll(viewContext: viewContext)

Ответ №1:

Вы должны внедрить управляемый контекст в свою функцию

 func deleteAll(viewContext: NSManagedObjectContext) {
    //…
}
 

Это также дает вам преимущество в том, что вы можете выбрать, из какого контекста удалять, если вы работаете с фоновым или дочерним контекстами

Ответ №2:

Добавьте этот параметр в свое представление

 @Environment(.managedObjectContext) var viewContext
 

Комментарии:

1. Спасибо, но у меня есть это на примете. Если быть точным, у меня есть: @Environment(.managedObjectContext) private var viewContext . Но даже без private этого ничего не получается. Пожалуйста, обратите внимание, что моя функция находится в отдельном файле. Не в представлении СвифтУИ. Это быстрый файл с одной только функцией.

2. Нет, это нехорошо. пожалуйста, переместите свою функцию в свой вид или модель представления.

3. Значит, я не могу хранить их в отдельных файлах? Как правильно разбить представление на более мелкие части, если у вас там много функций?

4. используйте расширение. создайте расширение своего представления как extension ContentView {...} и добавьте это расширение в отдельный файл. Глобальная функция — не очень хорошая идея.

5. Вы также можете сделать контекст представления статичным из файла Persistence.swift, а затем использовать его везде .