gpt4 book ai didi

ios - 从非事件状态恢复应用程序后,NSManagedObject 的 managedObjectContext 变为 nil

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:01:14 26 4
gpt4 key购买 nike

也许你能帮忙,我在其他问题中找不到类似的东西,所以我想我可能会遗漏一些明显的东西。

我有 Swift 中的 CoreData + iCloud 应用程序。

问题场景:

  1. 启动应用
  2. NSManagedObject 读取/更新
  3. 按“主页”(使应用处于非事件状态)
  4. 恢复应用
  5. NSManagedObject 读取/更新

如果我已经在我的设备上登录 iCloud,那么这就可以正常工作。

如果我从 iCloud 注销,那么所有应用程序都可以正常工作,如果我执行问题场景,那么在第 5 步中 NSManagedObject 的 managedObjectContext 为 nil,因此我无法对其进行任何更改,并且由于上下文丢失一旦我需要现有对象的上下文,它当然会崩溃。

我的问题:

  1. 为什么会像问题场景中那样发生这种情况?
  2. 如何解决此问题,以便在应用程序变为非事件状态后又处于事件状态且 iCloud 用户未登录时,CoreData 继续工作?

我的 CoreDataStack:

class CoreDataStack: CustomStringConvertible
{
static let sharedManager = CoreDataStack()
static let applicationDocumentsDirectoryName = "iCloud.com.myCompany.myAppID"
static let errorDomain = "CoreDataStack"

static let modelName = "DB"
static let storeName = "DB"
static var storeFileName: String
{
return storeName + ".sqlite"
}
var options : [String : AnyObject]?

var inMemory: Bool = false


var description: String
{
var desc = "context: \(self.managedObjectContext)\n" +
"modelName: \(CoreDataStack.modelName)" +
"storeURL: \(self.storeURL)"

desc += "\nPersistent Stores:\n"
for store in persistentStoreCoordinator.persistentStores
{
desc += "* \(store.URL!.absoluteString)"
}

return desc
}


lazy var managedObjectModel: NSManagedObjectModel =
{
let modelURL = NSBundle.mainBundle().URLForResource(modelName, withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()


lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator =
{
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

do
{
if self.inMemory
{
try coordinator.addPersistentStoreWithType(
NSInMemoryStoreType,
configuration: nil,
URL: nil,
options: nil)
} else
{
try coordinator.addPersistentStoreWithType(
NSSQLiteStoreType,
configuration: nil,
URL: self.storeURL,
options: self.options)
}
} catch var error as NSError
{
VTLog.error("Persistent Store Error: \(error)")
} catch
{
fatalError("Error creating Persistent Store!")
}
return coordinator
}()


/// The directory the application uses to store the Core Data store file.
lazy var applicationSupportDirectory: NSURL =
{
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask)
let applicationSupportDirectoryURL = urls.last!
let applicationSupportDirectory =
applicationSupportDirectoryURL.URLByAppendingPathComponent(applicationDocumentsDirectoryName)

do
{
let properties = try applicationSupportDirectory.resourceValuesForKeys([NSURLIsDirectoryKey])

if let isDirectory = properties[NSURLIsDirectoryKey] as? Bool where isDirectory == false
{
let description = NSLocalizedString("Could not access the application data folder.",
comment: "Failed to initialize applicationSupportDirectory.")
let reason = NSLocalizedString("Found a file in its place.",
comment: "Failed to initialize applicationSupportDirectory.")

throw NSError(domain: errorDomain, code: 201, userInfo:
[
NSLocalizedDescriptionKey: description,
NSLocalizedFailureReasonErrorKey: reason
])
}
} catch let error as NSError where error.code != NSFileReadNoSuchFileError
{
fatalError("Error occured: \(error).")
} catch
{
let path = applicationSupportDirectory.path!

do
{
try fileManager.createDirectoryAtPath(path, withIntermediateDirectories:true, attributes:nil)
}
catch
{
fatalError("Could not create application documents directory at \(path).")
}
}

return applicationSupportDirectory
}()


/// URL for the main Core Data store file.
lazy var storeURL: NSURL =
{
return self.applicationSupportDirectory.URLByAppendingPathComponent(storeFileName)
}()


lazy var managedObjectContext: NSManagedObjectContext =
{
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.persistentStoreCoordinator = self.persistentStoreCoordinator
return context
}()


// ****************************************
// MARK: - iCloud Sync
// ****************************************

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


private var ubiquitousChangesObserver: NSNotificationCenter?
{
didSet
{
oldValue?.removeObserver(
self,
name: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
object: persistentStoreCoordinator)

ubiquitousChangesObserver?.addObserver(
self,
selector: #selector(self.persistentStoreDidImportUbiquitousContentChanges(_:)),
name: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
object: persistentStoreCoordinator)


oldValue?.removeObserver(
self,
name: NSPersistentStoreCoordinatorStoresWillChangeNotification,
object: persistentStoreCoordinator)

ubiquitousChangesObserver?.addObserver(
self,
selector: #selector(self.persistentStoreCoordinatorWillChangeStores(_:)),
name: NSPersistentStoreCoordinatorStoresWillChangeNotification,
object: persistentStoreCoordinator)
}
}


@objc func persistentStoreDidImportUbiquitousContentChanges(notification: NSNotification)
{
VTLog.debug("Merging ubiquitous content changes")
VTLog.debug(notification)

self.managedObjectContext.performBlock
{
self.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)
}
}


@objc func persistentStoreCoordinatorWillChangeStores(notification: NSNotification)
{
VTLog.debug(notification)

if managedObjectContext.hasChanges
{
do
{
try managedObjectContext.save()
} catch let error as NSError
{
print("Error saving: \(error)", terminator: "")
}
}
managedObjectContext.reset()
}


// ***********************************************
// * Data: iCloud Container Actions
// ***********************************************

func deleteiCloudContainer()
{
VTLog.debug("Deleting iCloud Container...")

let currentStore = managedObjectContext.persistentStoreCoordinator!.persistentStores.last!

VTLog.debug("Located data store [\(currentStore)]")

managedObjectContext.reset()
VTLog.debug("managedObjectContext.reset() - OK")

do
{
try managedObjectContext.persistentStoreCoordinator?.removePersistentStore(currentStore)
VTLog.debug("removePersistentStore() - OK")
} catch let error as NSError
{
VTLog.error("Could not remove persistent store [\(currentStore)]: \(error)")
}

do
{
try NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(
currentStore.URL!, options: currentStore.options)
VTLog.debug("removeUbiquitousContentAndPersistentStoreAtURL() - OK")
} catch let error as NSError
{
VTLog.error("Could not remove Ubiquitous Content and Persistent Store at URL [\(currentStore)]: \(error)")
}
}


//*******************************************
// MARK: - Init
//*******************************************

init(inMemory:Bool = false)
{
self.inMemory = inMemory

self.options = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true,
NSPersistentStoreUbiquitousContentNameKey: CoreDataStack.storeName]
}

}

可能有帮助的其他信息:

  1. 所有这些都在模拟器上进行,无论版本如何:iOS 9.2、iOS 9.3。
  2. 当我登录到 iCloud 后,一切正常。
  3. 我注意到 DB.sqlite 文件实际上不存在于路径 storeURL 上,它是在如下所示的路径上创建的,但无论是否登录 iCloud 都一样,所以我不知道它是否应该是这样方式。
  4. 当我恢复应用程序时,我看到以下操作序列:

@ 2016-04-12 11:30:36: AppDelegate: applicationDidEnterBackground:133: (thread): {number = 10, name = main}

@ 2016-04-12 11:30:37: AppDelegate: applicationWillEnterForeground:141: (thread): {number = 11, name = main}

2016-04-12 11:30:37.150 Count Myself[57886:19968276] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: nobody~sim7CC36E42-82CB-5152-91BE-4DD26FE0A420:DB Using local storage: 1 for new NSFileManager current token (null)

@ 2016-04-12 11:30:37: CoreDataStack: persistentStoreCoordinatorWillChangeStores:203: NSConcreteNotification 0x7fd3e8d8fdc0 {name = NSPersistentStoreCoordinatorStoresWillChangeNotification; object = ; userInfo = { NSPersistentStoreUbiquitousTransitionTypeKey = 2; added = ( " (URL: file:///Users/maris/Library/Developer/CoreSimulator/Devices/F9A852DA-595C-4DE2-ADD7-7DECD7D814AD/data/Containers/Data/Application/107B6DB1-C4DC-4626-8933-DACD0575F184/Library/Application%20Support/iCloud.com.myCompany.myAppID/CoreDataUbiquitySupport/nobody~sim7CC36E42-82CB-5152-91BE-4DD26FE0A420/DB/local/store/DB.sqlite)" ); removed = ( " (URL: file:///Users/maris/Library/Developer/CoreSimulator/Devices/F9A852DA-595C-4DE2-ADD7-7DECD7D814AD/data/Containers/Data/Application/107B6DB1-C4DC-4626-8933-DACD0575F184/Library/Application%20Support/iCloud.com.myCompany.myAppID/CoreDataUbiquitySupport/nobody~sim7CC36E42-82CB-5152-91BE-4DD26FE0A420/DB/local/store/DB.sqlite)" ); }} (thread): {number = 12, name = main}

@ 2016-04-12 11:30:37: AppDelegate: applicationDidBecomeActive:152: context: modelName: DBstoreURL: file:///Users/maris/Library/Developer/CoreSimulator/Devices/F9A852DA-595C-4DE2-ADD7-7DECD7D814AD/data/Containers/Data/Application/107B6DB1-C4DC-4626-8933-DACD0575F184/Library/Application%20Support/iCloud.com.myCompany.myAppID/DB.sqlite Persistent Stores: * file:///Users/maris/Library/Developer/CoreSimulator/Devices/F9A852DA-595C-4DE2-ADD7-7DECD7D814AD/data/Containers/Data/Application/436959B5-7850-4156-AB3D-A11BE72FF1AF/Library/Application%20Support/iCloud.com.myCompany.myAppID/CoreDataUbiquitySupport/nobody~sim7CC36E42-82CB-5152-91BE-4DD26FE0A420/DB/local/store/DB.sqlite

  1. 当我这样设置时出现问题:stack.updateContextWithUbiquitousContentUpdates = true但是,如果我不将其设置为 true,我想我不会立即从 iCloud 获取更新。
  2. 在 GitHub 上查看演示该问题的 Xcode 项目:https://github.com/marisveide/iCloudCoreDataProblem (阅读顶部的 AppDelegate.swift 文件注释)看到单独分支中的代码更改解决方案不会丢失上下文真是太棒了。

最佳答案

当您退出并重新启动时,应用程序将从内存中删除,因此持久存储和上下文会再次创建并将它们链接在一起。

当您将背景置于背景中,然后提出未发生的情况时,商店和上下文仍然存在。看起来这里发生的是持久存储文件被更改并且上下文与其断开连接(这是一个猜测,我没有测试过)。

因此,看起来在 persistentStoreCoordinatorWillChangeStores 中您应该真正销毁上下文并创建一个新上下文。这也意味着销毁所有来自旧上下文的托管对象并从新上下文获取新版本(假设它们仍然存在)。

关于ios - 从非事件状态恢复应用程序后,NSManagedObject 的 managedObjectContext 变为 nil,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36567966/

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