gpt4 book ai didi

swift - UITabBarController应用(Swift 1.2)中用于iCloud同步的核心数据堆栈实现

转载 作者:行者123 更新时间:2023-11-28 09:09:49 28 4
gpt4 key购买 nike

在过去的4天里,我一直在尝试为我的Swift 1.2应用程序实现一个带有iCloud sync的核心数据堆栈,但我确实需要一些帮助。
以前,我使用的是从应用程序中的任何地方访问的全局管理上下文;知道这是一个糟糕的实现,现在我添加了iCloud sync,所以我决定删除它,尽管应用程序运行良好。
到目前为止,我已经实现了一个新的工作核心数据堆栈,在设备之间实现了体面但并不完美的云同步。
现在我面临两个问题:
有时,一些对象不同步。
考虑到我的应用程序的特殊结构(稍后我将解释),我不知道在我的代码中应该如何处理核心数据在用户登录或退出iCloud时发送的通知。
但是,在解决这些问题之前,如果合适的话,我会非常感谢对我目前所做工作的一些验证,主要是为了确认我正在写这篇文章:因为我已经花了很多时间修改我的核心数据堆栈,在继续之前,我想知道我是否正确地传播了上下文(我的应用程序不符合我在网上找到的任何教程,所以我不得不临时凑合一下),或者如果我犯了一些基本的错误,将危及可靠的同步或未来的发展。
我的应用程序的结构如下:
UITabBarViewController作为初始视图控制器
第一个选项卡:UIViewController(应用程序启动时显示)
第二个选项卡:aUITableViewController嵌入aUINavigationController
第三个选项卡:另一个UITableViewController嵌入另一个UINavigationController
我有一个CoreDataStack.swift类,代码如下:

import CoreData

@objc class CoreDataStack : Printable {

let context : NSManagedObjectContext
let psc : NSPersistentStoreCoordinator
let model : NSManagedObjectModel
let store : NSPersistentStore?

var description : String {
return "context: \(context)\n" + "model: \(model)"
}

var applicationDocumentsDirectory : NSURL = {
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) as! [NSURL]
return urls[0]
}()

init() {

let modelURL = NSBundle.mainBundle().URLForResource("MyDataModel", withExtension:"momd")
model = NSManagedObjectModel(contentsOfURL: modelURL!)!
psc = NSPersistentStoreCoordinator(managedObjectModel: model)
context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
context.persistentStoreCoordinator = psc
let documentsURL = applicationDocumentsDirectory
let storeURL = documentsURL.URLByAppendingPathComponent("MyApp.sqlite")

let options = [NSPersistentStoreUbiquitousContentNameKey: "MyApp", NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
store = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: options, error:&error)

if store == nil {
let dict = NSMutableDictionary()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict as [NSObject : AnyObject])
println("Error adding persistent store: \(error), \(error!.userInfo)")
abort()
}
}

func saveContext() {
var error: NSError? = nil
if context.hasChanges && !context.save(&error) {
println("Could not save: \(error), \(error!.userInfo)")
}
}

var updateContextWithUbiquitousContentUpdates: Bool = false {
willSet {
ubiquitousChangesObserver = newValue ? NSNotificationCenter.defaultCenter() : nil
}
}

private var ubiquitousChangesObserver : NSNotificationCenter? {
didSet {
oldValue?.removeObserver(self, name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: psc)
ubiquitousChangesObserver?.addObserver(self, selector: "persistentStoreDidImportUbiquitousContentChanges:", name: NSPersistentStoreDidImportUbiquitousContentChangesNotification, object: psc)
}
}

func persistentStoreDidImportUbiquitousContentChanges(notification: NSNotification) {
println("Merging ubiquitous content changes")
context.performBlock {
self.context.mergeChangesFromContextDidSaveNotification(notification)
}
}
}

在AppDelegate.swift中,我在 var window: UIWindow?下面添加了以下代码:
lazy var coreDataStack = CoreDataStack()

coreDataStack.updateContextWithUbiquitousContentUpdates = true

// The following code is the way I found to propagate the managed context of the stack instantiated above in all the ViewControllers of the UITabBarController, including those embedded in the two NavigationControllers;
// since in the future I'll probably need some flexibility in term of adding / rearranging the VCs in the TabBar, I kind of like this way to pass around the context.
// I could have also passed the context to the CustomTabBarViewController and from there do the same thing, but I figured I could just pass the context from AppDelegate, since I already can access all the ViewControllers from here with the following code.
var tabBarController = self.window!.rootViewController as! CustomTabBarViewController
for eachViewController in tabBarController.viewControllers! {
if eachViewController.isKindOfClass(CustomViewController){
(eachViewController as! CustomViewController).passedManagedContext = coreDataStack.context // Context is passed to the VC of 1st tab
}
if eachViewController.isKindOfClass(UINavigationController){
var firstNavController = tabBarController.viewControllers![1] as! UINavigationController
for tvc in firstNavController.viewControllers! {
if tvc.isKindOfClass(FirstCustomTableViewController) {
(tvc as! FirstCustomTableViewController).passedManagedContext = coreDataStack.context // Context is passed to the TableVC inside the NavigationController in tab 2
}
}
var secondNavController = tabBarController.viewControllers![2] as! UINavigationController
for tvc in secondNavController.viewControllers! {
if tvc.isKindOfClass(SecondCustomTableViewController) {
(tvc as! SecondCustomTableViewController).passedManagedContext = coreDataStack.context // Context is passed to the TableVC inside the NavigationController in tab 3
}
}
}
}

// Of course, in applicationDidEnterBackground: and applicationWillTerminate: I save the context; obviously, I also save the context, when appropriate, from the other ViewControllers.

有了这个结构,我在AppDelegate中实例化我的堆栈,然后从那里把它传播到TabBar的3个元素中;从这些元素中,我再次将上下文传播到我存在的所有其他ViewController。我在控制台上记录了所有的上下文,我可以确认它始终是相同的。
事实上,这段代码的应用程序是有效的。
我不能说它是完美的,因为正如我所说的,有时一些对象不同步,但我怀疑这些对象不同步的原因是另一个(简单地说,我有2个 NSManagedObject子类;子类1的对象有一个子类为属性的对象;如果我用一个现有的子类对象作为属性创建一个新的子类1对象,则同步是很好的;如果i还要创建一个新的Subasss2对象,保存它并立即将其设置为Subasss1的属性,有时Subasss2对象不会在另一个设备上同步,而Subasss1会同步并错过该属性。。。我可以稍后再做)。
在深入研究这个同步问题之前,我真的很想知道我迄今为止在堆栈上所做的工作是否有意义,或者它是否很糟糕,是否需要屏蔽。
然后,如果上面所有的代码都不可怕,如果偶尔错过对象同步的原因是我怀疑的,那么另一个问题就来了,这是一个很大的问题:我应该把代码放在哪里来处理用户登录或退出iCloud时发生的通知( NSPersistentStoreCoordinatorStoresWillChangeNotificationNSPersistentStoreCoordinatorStoresDidChangeNotification)?
我试着在AppDelegate和CoreDataStack类中,根据教程书中的核心数据,将我编写的方法(没有实际的功能,目前我只是登录到控制台才知道我到了那里)放在上面,但在这两种情况下,当我在应用程序运行时从iCloud登录或退出时,应用程序在没有一行代码的情况下崩溃控制台,所以我不知道这个问题。
也许我应该把处理这些通知的方法放在所有的ViewControllers中,因为fetch请求发生在那里,UI从那些类中更新,但是我不会传递整个coreDataStack对象,只传递上下文。。。所以我漏掉了一些东西。我应该传递整个堆栈,而不仅仅是上下文吗?可以处理来自CoreDataStack的那些通知吗,还是应该从AppDelegate执行?
任何帮助都将不胜感激。。。
提前谢谢,如果我的问题不清楚,请原谅(我是个初学者,英语不是我的主要语言…)。
另外,感谢您花时间阅读这个长问题!
@cdf1982型

最佳答案

我认为问题在于iCloud+CD从未正常工作过。这不是一个开发者代码的问题,问题是苹果公司的iCloud+CD实现失败了。

关于swift - UITabBarController应用(Swift 1.2)中用于iCloud同步的核心数据堆栈实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29613824/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com