我在应用程序商店中有一个应用程序,并使用日志服务来获取崩溃日志和相关的日志数据.我看到一个间歇性的崩溃(受影响的用户数低,每个用户的崩溃次数低),但令我感到困惑.
这些崩溃中发生的事情如下:
应用程序启动并初始化Core Data堆栈
应用程序尝试使用以下代码将SQL存储添加到NSPersistentStoreCoordinator(storeURL有效):
NSDictionary *options = @{
NSMigratePersistentStoresAutomaticallyOption : @(YES),
NSInferMappingModelAutomaticallyOption : @(YES)
};
sqlStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error];
Run Code Online (Sandbox Code Playgroud)添加此商店时会发生以下错误之一:
NSError:
Domain = NSCocoaErrorDomain
Code = 256"操作无法完成.(Cocoa错误256.)"
UserInfo = 0x1dd946a0 {NSUnderlyingException =授权被拒绝,NSSQLiteErrorDomain = 23}
要么
NSError:
Domain = NSCocoaErrorDomain
Code = 256"无法完成操作.(Cocoa error 256.)"
UserInfo = 0xc6525d0 {NSUnderlyingException = disk I/O error,NSSQLiteErrorDomain = 10}
在这种情况下,应用程序将崩溃b/c应用程序运行所需的SQL存储.我可以尝试通过尝试新的storeURL来优雅地处理此故障,但我不希望用户丢失现有数据.此外,我从未亲自重现此问题,并且基于受影响的用户数量和崩溃日志,我认为这是一个影响较小的问题,并且不会在随后的应用程序启动时重复出现.
我希望那里有一位核心数据专家,提供一些关于如何调试和预防/处理这些条件的建议.我的核心数据堆栈初始化代码直接来自xcode项目生成器,我排除了任何并发问题,因为持久性存储协调器只初始化一次(启动时),并且此错误发生在此初始化中.
很高兴提供更多相关的代码/信息.
谢谢!
在我的应用程序中,我能够清除数据库中的所有数据.完成此操作后,将解析捆绑的JSON,然后将其保存到数据库(以便将数据库返回到默认状态).解析和保存此JSON的操作在任何情况下都可以正常工作,除非在清除并重新创建持久性存储之后,在这种情况下我得到'NSInvalidArgumentException',原因:'无法从此NSManagedObjectContext的协调器访问对象的持久存储'.在保存在后台上下文中后尝试在主线程上下文中调用mergeChangesFromContextDidSaveNotification时抛出此异常.
重新创建存储是在主线程上执行的,因为解析和保存总是在后台线程上进行.这是我的托管对象上下文的getter,以确保线程安全:
- (NSManagedObjectContext *)managedObjectContext {
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext *threadContext = threadDictionary[ckCoreDataThreadKey];
if (!threadContext) {
threadContext = [self newManagedObjectContext];
threadDictionary[ckCoreDataThreadKey] = threadContext;
}
return threadContext;
}
Run Code Online (Sandbox Code Playgroud)
newManagedObjectContext方法为所有新实例提供相同的NSPersistentStoreCoordinator对象.
以下是用于清除存储的代码(始终在主线程上执行):
[self.managedObjectContext lock];
[self.managedObjectContext reset]; //to drop pending changes
//delete the store from the current managedObjectContext
if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:error]) {
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:error];
[[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:error]; //recreates the persistent store
[self addSkipBackupAttributeToItemAtURL:storeURL];
}
[self.managedObjectContext unlock];
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这个相同的代码在其他项目中运行良好,除了数据内容之外没有其他区别.任何帮助是极大的赞赏!
我正在开发一个分阶段推出的应用程序.对于每个sprint,都有数据库更改,因此已实现核心数据迁移.到目前为止,我们已经有3个阶段发布.每当连续升级时,应用程序运行正常.但每当我尝试从版本1升级到版本3时,都会发生'无法添加持久存储'错误.有人可以帮我解决这个问题吗?
我正在将我的 iOS 应用程序迁移到使用NSPersistentContainer. 默认情况下,此类将其持久存储文件定位在Library/Application Support目录中;以前我的商店文件存储在该Documents目录中。
我添加了一些代码来移动存储文件(如果在旧目录中找到它们):
func moveStoreFromLegacyLocationIfNecessary(toNewLocation newLocation: URL) {
// The old store location is in the Documents directory
let legacyStoreLocation = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("books.sqlite")
// Check whether the old store exists and the new one does not
if FileManager.default.fileExists(atPath: legacyStoreLocation.path) && !FileManager.default.fileExists(atPath: newLocation.path) {
print("Store located in Documents directory; migrating to Application Support directory")
let tempStoreCoordinator = NSPersistentStoreCoordinator()
try! tempStoreCoordinator.replacePersistentStore(at: newLocation, destinationOptions: nil, withPersistentStoreFrom: legacyStoreLocation, …Run Code Online (Sandbox Code Playgroud) 我正在尝试在基于UIManagedDocument的应用程序中预加载持久性存储来处理核心数据.
持久存储我尝试在应用程序B中使用,由于应用程序A"生成"并填充.在应用程序A和BI中都使用Justin Driscoll的UIManagedDocument处理程序(可在此处获得,感谢Mister Driscoll!).所有在app A中完美运行
基于此线程中解释的技术:使用UIManagedDocument在iOS 5中预加载核心数据数据库,我尝试将持久性存储放在B的应用程序包中,并在需要时将此存储复制到文档文件夹中(如果没有完成)在实例化之前的init中.
从捆绑到文档的复制都没问题(我尝试了不同的方法并通过finder和nslog检查了创建),但我无法打开"文档".应用程序不会崩溃,显示视图但表是空的(我使用与app A完全相同的代码,使用相同的fetchedResultsController).首先我认为复制持久存储是空的然后我意识到我只是无法正确打开文档/复制持久存储)=>文档状态= 5,意味着UIDocumentStateClosed和UIDocumentStateSavingError的错误(如果我正确解释它? )
(注意:我也尝试直接从bundle中实例化并打开文档,我遇到了同样的问题:doc state = 5)
所以...三天与这个文件状态= 5战斗,并没有关于修复什么的线索
我想我放入应用程序B包中的文件有问题(目前我从finder拖放到xcode,选中"为任何添加的文件夹创建文件夹引用")也许这是关于某些选项,元数据或文件权限或......
关于调查什么的任何想法?
(我不认为这是关于下面的代码但是......)这是我如何初始化(基于Justin Driscoll处理程序.只有custo是:我检查文档文件夹中是否有商店包,如果不是我创建它在捆绑中的文件)
- (id)init
{
self = [super init];
if (self) {
self.document = nil;
NSLog(@"--- INIT ---");
// On vérifie si il y a un dossier "My-Default-Document-As-Database" (notre persitent store) dans le dossier "Documents"
NSString *docDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *docFolderPath = [docDirectory stringByAppendingPathComponent:@"My-Default-Document-As-Database"];
if (![[NSFileManager defaultManager] fileExistsAtPath:docFolderPath]) {
NSError *error = nil;
NSLog(@"Pas …Run Code Online (Sandbox Code Playgroud) 我正在实现一个自定义NSIncrementalStore子类,它使用关系数据库进行持久存储.我仍在努力的一件事是支持乐观锁定.
(可以在下面的问题中跳过这个冗长的描述)
我分析了Core Data的SQLite增量存储如何通过检查它生成的SQL日志来解决这个问题,并得出以下结论:
数据库中的每个实体表都有一个Z_OPT列,它指示从1(初始插入)开始修改此实体(行)的特定实例的次数.
每次修改托管对象时,其相应数据库行中的Z_OPT值都会递增.
存储维护NSIncrementalStoreNode实例的缓存(在Core Data docs中称为行缓存),每个实例的版本属性等于由托管对象的行上的先前SELECT或UPDATE SQL查询返回的Z_OPT值.
当从NSManagedObjectContext返回托管对象时(例如,通过对其执行NSFetchRequest),MOC会创建包含此版本号的此对象的快照.
修改或删除对象时,Core Data通过比较缓存的行和对象快照的版本,确保它未在上下文之外被修改或删除.当-save:在对象所属的上下文上调用时,所有这些都会发生.如果版本不同,则基于集合并策略检测并处理合并冲突.
保存MOC时,为每个修改/删除的对象调用-newValuesForObjectWithID:withContext:error:方法,后者又返回带有版本号的NSIncrementalStoreNode.然后将此版本与快照的版本进行比较,如果它们不同,则保存将因适当的合并冲突而失败(至少使用默认合并策略).
这个简单的用例适用于我的商店,因为-newValuesForObjectWithID:withContext:error:首先检查行缓存,如果在其他上下文中使用相同的商店实例同时修改了该对象,那么这就足够了.如果是这种情况,则缓存包含具有更高版本号的更新行,该行足以检测冲突.
但是,我如何检测到底层数据库已经在我的商店外被修改,可能是由使用相同数据库文件的其他应用程序或其他商店实例?我知道这是一个不常见的边缘情况,但Core Data正确处理它,我宁愿做同样的事情.
Core Data的商店使用这些SQL查询来更新/删除对象的行:
UPDATE ZFOO SET Z_OPT=Y, (...) WHERE (...) AND Z_OPT=X
DELETE FROM ZFOO WHERE (...) AND Z_OPT=X
Run Code Online (Sandbox Code Playgroud)
其中:
X - 商店最后知道的版本号(来自缓存)
Y - 新版本号
如果此类查询失败(没有行受影响),则会在商店的缓存中更新该行,并将其版本与先前缓存的版本进行比较.
我的问题是:自定义NSIncrementalStore如何通知Core Data一些更新/删除/锁定的对象发生了乐观锁定失败?这是这是唯一能告诉大家,当它处理店里NSSaveChangesRequest …
我已经阅读了一些文章NSIncrementalStore,我仍然对整个概念感到困惑.在这篇文章中我们可以读到:
从本质上讲,您现在可以创建一个自定义子类
NSPersistentStore,这样您NSFetchRequest就可以运行一个定义的方法,而不是命中本地SQLite数据库,该方法可以执行任意操作以返回结果(例如发出网络请求).
到目前为止,我认为NSIncrementalStore是访问远程数据并在本地保存/缓存的完美解决方案.现在,我推断它只是一种用于访问远程数据的解决方案.
如果我是对的,我会感谢任何关于某些解决方案的建议.如果我错了,魔法在哪里以及如何实现它?NSIncrementalStore上的每篇文章/文章/教程都显示了从服务器提取数据的难易程度,但他们都没有提供有关缓存离线查看内容的单一线索.
回答一下,让我们考虑一个常见的场景,即应用程序应该从Internet下载一些数据,显示并保存在本地,以便用户可以离线使用该应用程序.
此外,我不承诺使用NSIncrementalStore或其他东西.我只是在寻找最好的解决方案,这个类被这个领域的一些最好的专家描述为一个.
我的iOS中的核心数据有一些奇怪的问题,我似乎无法重现,它只是偶尔会发生一些报告它的用户.我从iOS崩溃报告中得到的错误:
CoreData: - [NSPersistentStoreCoordinator _coordinator_you_never_successfully_opened_the_database_so_saving_back_to_it_is_kinda_hard:] + 56
这是一个截图(省略产品名称):
困难的是我没有得到任何关于该错误的搜索结果.这是我的(相关)代码:
保存:
-(void)save
{
if(!self.horecaMOC.hasChanges)return;
NSError *error;
[self.horecaMOC save:&error];
if(error)
{
NSLog(@"save error %@",error.localizedDescription);
}
}
Run Code Online (Sandbox Code Playgroud)
商务部:
-(NSManagedObjectContext*)horecaMOC
{
if(!_horecaMOC)
{
NSPersistentStoreCoordinator *coordinator = self.horecaPSC;
if (coordinator != nil) {
_horecaMOC = [[NSManagedObjectContext alloc] init];
[_horecaMOC setPersistentStoreCoordinator:coordinator];
}
}
return _horecaMOC;
}
Run Code Online (Sandbox Code Playgroud)
PSC:
-(NSPersistentStoreCoordinator*)horecaPSC
{
if(!_horecaPSC)
{
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"horeca.sqlite"];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSError *error = nil;
_horecaPSC = [[NSPersistentStoreCoordinator …Run Code Online (Sandbox Code Playgroud) 我encrypted-core-data用来加密所有持久化的数据,以前很简单CoreData.persistentStoreCoordinator创建代码如下.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *oldStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"VistaJetApp.sqlite"];
NSURL *newStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"VistaJet.sqlite"];
NSError *error = nil;
NSString *currentPassword = [[VJAesCryptoWrapper getInstance] getCurrentPassword];
NSDictionary *options = [self getEncryptedStoreOptionsWithPassword:currentPassword andDatabaseStore:newStoreURL];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
//if old store not exists , it means fresh installation
if([[NSFileManager defaultManager] fileExistsAtPath:oldStoreURL.path] == NO) {
if (![_persistentStoreCoordinator addPersistentStoreWithType:EncryptedStoreType configuration:nil URL:newStoreURL options:options error: &error]) {
}
} …Run Code Online (Sandbox Code Playgroud) app-store core-data-migration nspersistentstore keychainitemwrapper encrypted-core-data-sql
我目前正在对一个与 Core Data 交互的层进行单元测试。它保存、删除和更新Item对象。但是,我的测试试图保存一些Items 然后执行批量删除的测试一直失败。
这是Item:
extension Item {
// MARK: - Properties
@NSManaged public var date: NSDate
@NSManaged public var isTaxable: Bool
@NSManaged public var name: String
@NSManaged public var price: NSDecimalNumber
@NSManaged public var quantity: Double
// MARK: - Fetch Requests
@nonobjc public class func fetchRequest() -> NSFetchRequest<Item> { return NSFetchRequest<Item>(entityName: "Item") }
// MARK: - Validation
// Manual validation for `Decimal` values is needed. A radar is still open, which is …Run Code Online (Sandbox Code Playgroud) 我一直在努力将iCloud存储迁移到应用程序沙箱中的本地存储.代码如下所示(为清楚起见,错误处理代码已被删除):
NSPersistentStore *iCloudStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:legacyStoreUrl options:options error:&error];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *targetStoreUrl = [self localStorageUrl];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
[_persistentStoreCoordinator migratePersistentStore:legacyStore toURL:targetStoreUrl options:options withType:NSSQLiteStoreType error:nil];
Run Code Online (Sandbox Code Playgroud)
此时我们已成功将iCloud存储迁移到应用程序沙箱中的新位置,但iCloud和旧的sqlite文件中仍有数据...以下行删除了sqlite文件
[fileManager removeItemAtURL:legacyStoreUrl error:nil]
Run Code Online (Sandbox Code Playgroud)
因此,在运行所有这些后,我的文件系统和持久性商店看起来很好,据我所知.缺少的一点是存储在iCloud中的数据不会从iCloud中删除(尽管应用程序不再访问它).以编程方式删除iCloud数据还需要做些什么?苹果iCloud文档提到删除事务日志但我没有看到我的Documents文件夹中需要清理的任何其他文件.任何帮助深表感谢!
更新:
最初使用以下选项设置iCloud存储:
NSURL *ubiquityContainerUrl = [fileManager URLForUbiquityContainerIdentifier:nil];
NSString* coreDataCloudContent = [[ubiquityContainerUrl path] stringByAppendingPathComponent:@"data"];
NSURL *coreDataUrl = [NSURL fileURLWithPath:coreDataCloudContent];
options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
@"MyAppName.store", NSPersistentStoreUbiquitousContentNameKey,
coreDataUrl, NSPersistentStoreUbiquitousContentURLKey,
nil];
Run Code Online (Sandbox Code Playgroud) NSManagedObjectContext保存子项并将更改推送到父项时如何解决冲突NSManagedObjectContext?
例如,假设您正在使用来自服务器的数据在子上下文NSManagedObject Person中将属性设置age为 18进行更新NSPrivateQueueConcurrencyType。在同一时间,同一NSManagedObject Person age属性由在父用户更新到20的值NSManagedObjectContext与NSMainQueueConcurrencyType。
在两次更新之后,都会在传播到父级的子上下文上调用保存NSManagedObjectContext。
此时的年龄值是多少?孩子会NSManagedObjectContext覆盖父母NSManagedObjectContext吗?在NSMergePolicies这里申请吗?
concurrency core-data nsmanagedobjectcontext ios nspersistentstore
NSManagedObjectContext调用持久存储和父上下文设置和保存时会发生什么?它会将数据逐个推送到持久存储和父上下文吗?或者它会同时进行吗?或核心数据是否会引发抱怨异常?
API不直接阻止一个人为给定的上下文设置两个"父母".