使用AppDelegate作为单例定义Core Data的上下文

问题描述 投票:1回答:1

我正试图让我的脑袋围绕核心数据的NSManagedObjectContext。如果在创建新项目时选中Core Data复选框,则Xcode 10.1提供了大量样板。但我觉得有点混乱,如何为每个视图控制器设置当前上下文。我想我有更好的方法,我正在寻求建议,以确认,或让我回到正确的轨道。

例如,在样板文件AppDelegate代码中,didFinishLaunchingWithOptions为MasterViewController提供了这样的上下文:

let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController
controller.managedObjectContext = self.persistentContainer.viewContex

在MasterViewContoller中,第一次使用上下文从fetchedResultsController中获取它并且有代码来保存提供的上下文,即使AppDelegate已经有一个saveContext()函数可用于执行相同的操作:

@objc
func insertNewObject(_ sender: Any) {
    let context = self.fetchedResultsController.managedObjectContext
    let newEvent = Event(context: context)

    // If appropriate, configure the new managed object.
    newEvent.timestamp = Date()

    // Save the context.
    do {
        try context.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)")
    }
}

在我的具有多个视图控制器的应用程序中,我犯了一些错误,试图在每个需要它的地方重新声明或移交上下文,因此不得不应对由于无意中有多个上下文飞来造成的错误。

所以我的问题是:我犯了一个错误,或者是否存在以下方法的缺点:

1)使AppDelegate成为单身人士:

class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {

var window: UIWindow?

static let shared = AppDelegate()
…

2)在每个需要它的类中,总是定义上下文(我假设我只需要一个),如下所示:

let context = AppDelegate.shared.persistentContainer.viewContext

3)每当需要保存上下文时,请执行以下操作:

AppDelegate.shared.saveContext()

这似乎更简单,更清晰,更不容易出错,并且似乎在我的实现中起作用。我有没有看到这个问题?

ios swift core-data nsmanagedobjectcontext
1个回答
0
投票

说实话,Apple示例/模板对于初学者来说总是不好的例子,因为它们只显示一件事并且在休息时“破解”(例如,强行打开所有内容)。初学者倾向于只复制这种方法。

免责声明:我在谈论中大型应用程序。您总是可以在小型应用程序中打破此规则和建议,因为不使用它们可以更容易并且导致更简单的应用程序。

Make the AppDelegate a singleton:

在99%你不应该自我实例化AppDelegate。它由UIApplication / @UIApplicationMain注释为您处理。

AppDelegate已经是单身人士,因为每个应用程序在整个生命周期中只有一个代表。您可以通过UIApplication.shared.delegate as? AppDelegate访问它。

但你不应该。 AppDelegate通过为系统和代码之间的通信提供入口点,在每个应用程序中扮演特定角色,您不应该向其添加其他角色(作为句柄数据库)。在大多数情况下,在代码库中的某个地方访问代码异味和糟糕的架构。

Separating CoreData stack

DataBase访问是很好地使用Singleton模式的少数几个例子之一。但是,您应该制作单独的服务,而不是使用AppDelegate,它只负责处理与coredata的通信(例如创建和处理堆栈,发送查询等)。

所以CoreDataService是要走的路。

Accessing core data

使用单例并不意味着你可以通过输入Singleton.shared来访问它。这将大大降低组件的可测试性,并使它们与单例高度耦合。

相反,你应该阅读有关Dependency injection principle并注入你的单身人士。例如:

class MyViewController: UIViewController {
    let dataBaseManager: CoreDataService
    init(with dataBaseManager: CoreDataService) {
        self.dataBaseManager = dataBaseManager
        super.init(nibName: nil, bundle: nil)
    }
}

理想情况下,你应该更进一步到SOLID并向控制器提供它真正需要的东西:

protocol EventsProvider {
    func getEvents(with callback: [Event] -> Void)
}

extension CoreDataService: EventsProvider {
    func getEvents(with callback: [Event] -> Void) { 
        // your core data query here
    }
}

class MyViewController: UIViewController {
    let eventsProvider: EventsProvider
    init(with eventsProvider: EventsProvider) {
        self.eventsProvider = eventsProvider
        super.init(nibName: nil, bundle: nil)
    }
}

let vc = MyViewController(with: CoreDataService.shared)

Multiple contexts

拥有多个NSManagedObjectContext可以很方便并提高性能,但前提是您知道如何使用它们。 这是更高级的主题,所以你现在可以忽略它。 你可以在Core Data Programming Guide上阅读它

© www.soinside.com 2019 - 2024. All rights reserved.