【问题标题】:Saving segue passed managedObjectContext in Swift在 Swift 中保存 segue 通过 managedObjectContext
【发布时间】:2016-01-30 13:41:40
【问题描述】:

假设我有一个视图控制器 (VCA),它连接到另一个视图控制器 (VCB)。在准备 segue 时,VCA 传递其 managedObjectContext(即遵循“告诉不问”约定)。 VCA 还有一个函数saveManagedObjectContext() 执行保存和错误处理。

所以,在 VCA 中:

let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

...

func saveManagedObjectContext() {
    if managedObjectContext.hasChanges {
        do {
            try managedObjectContext.save()
        } catch let error as NSError {
            print("Could not save \(error), \(error.userInfo)")
            abort()
        }
    }
}

...

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    ...

    if let vcb = segue.destinationViewController as? VCB {
        vcb.managedObjectContext = managedObjectContext
    }

    ...

}

在 VCB 中:

var managedObjectContext: NSManagedObjectContext? = nil

假设 VCB 将一些实体添加到从 VCA 传递给它的 managedObjectContext

func createSomeEntity() {
    let entity = NSEntityDescription.entityForName("SomeEntity", inManagedObjectContext: managedObjectContext!)
    something = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedObjectContext) as? SomeEntity
}

是否有任何(正确的)方法可以从 VCA 调用 saveManagedObjectContext() 函数,而不必将函数复制到 VCB?

谢谢

【问题讨论】:

  • 您可以传递应用程序委托实例来访问整个核心数据堆栈,而不是传递托管对象上下文,但是 - 因为您使用的是检索对应用程序的引用的方式无论如何在 VCA 中委托——什么都不传递,在 VCB 中做同样的事情。还可以考虑使用共享单例类来管理 Core Data 的东西。
  • 我读到在不同的视图控制器中不断向应用程序委托请求托管对象上下文是“示意图不好”,您应该从顶部传递它的引用,即“告诉不要问”方法...
  • 是的,但是您已经违反了 VCA 中的规则;-)
  • 当然 - 但 VCA 可能是我的根控制器或从应用程序委托 application(application: UIApplication, didFinishLaunchingWithOptions 传递上下文...那么这样可以吗?
  • 是的,那是个好地方。

标签: swift core-data


【解决方案1】:

另一种方法是单例类。

创建一个新的 Swift 文件,将预定义的代码替换为

class CoreDataManager: NSObject {

  // MARK: - Shared Instance

  class var sharedManager : CoreDataManager {
    struct Singleton {
      static let instance = CoreDataManager()
    }
    return Singleton.instance
  }

  // MARK: - Core Data stack

  lazy var ...

}

然后将lazy var ... 替换为来自 AppDelegate 的整个核心数据堆栈。

现在您可以使用

从任何地方访问 Core Data
let managedObjectContext = CoreDataManager.sharedManager.managedObjectContext 

或调用保存操作

CoreDataManager.sharedManager.saveAction(self)

【讨论】:

    【解决方案2】:

    关于“告诉不要问”的要点。许多 Apple 示例代码都在宣传这个概念。 然而,近年来,Apple 还提供了带有处理对象图的 Core Data 堆栈类的示例代码,实际上放弃了“告诉不问”模式

    此外,在许多流行且广受赞誉的开源项目中,都使用了这种模式。在大多数情况下,您减少了代码并且仍然有一个健壮的解决方案。例如,在具有嵌套背景上下文的更复杂的项目中,它通常是唯一可行的设置。

    因此,我建议创建一个处理核心数据堆栈的CoreDataManager 类,或者对于不太复杂的应用程序(单主线程上下文)使用应用程序委托。

    请注意,在 Swift 中,您确实可以使用全局变量(您应该谨慎使用!)使这变得非常简洁。例如,在 AppDelegate.swift 之上,您可以编写

    let SharedAppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
    

    (我喜欢将我的全局单例大写)。您可以按如下方式使用它

    do { try SharedAppDelegate.context.save() } catch {}
    

    【讨论】:

    • 对不起 - 如果我总是要求 ShareAppDelegate,这如何符合“告诉不要问”?所以在 VCA 中我通过let managedObjectContext = SharedAppDelegate.managedObjectContext 获得对上下文的引用,然后在 VCB 中我必须做同样的事情......或者我是否从偏移量获得一个托管上下文引用,将其传递给后续视图控制器,然后保存在需要的任何视图控制器中使用SharedAppDelegate.saveContext() 函数?谢谢
    • 它没有。这就是我的观点。 “告诉不问”几乎被苹果自己抛弃了。
    • 好的 - 沟通不畅。所以要确认一下:您和@vadian 建议放弃“告诉不要问”方法,而只是动态创建实例或直接访问SharedAppDelegate 单例?
    • 是的,或者提到的单独的类。你甚至可以更进一步,定义一个全局函数saveObejctGraph()。 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2020-09-04
    • 2017-12-01
    • 1970-01-01
    相关资源
    最近更新 更多