我发现今天的内存泄漏在我的主 NSManagedObjectContext 中调用 executeFetchRequest 时表现出来。我终于发现,已知的攻击者来自于我的NSManagedObjectContext将其父上下文分配给私有托管对象上下文。
注释掉具有我的主上下文的代码行分配私有父类,而是直接指向NSPersistentStoreCoordinator释放我的应用程序的所有内存泄漏。
我离开了以下文章:http://martiancraft.com/blog/2015/03/core-data-stack/,了解如何在我的应用程序中实现CoreData的设计模式。我真的很喜欢将私有队列专门用于编写磁盘,并将主上下文作为使用UI时调用的单一来源。
所以我的问题是,有没有其他人遇到这个问题,如果是这样,你知道修复而不是仅仅为了避免内存泄漏而只处理一个上下文吗?
以下是我的CoreDataStack中显示两个上下文变量的部分。
private lazy var privateManagedObjectContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
moc.persistentStoreCoordinator = self.persistentStoreCoordinator
return moc
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
// Commenting out #1 and unCommening #2 prevents the leak from happening
// However when the reverse happens and we create the private context, a memory leak occurs first thing in the app.
// #1
// managedObjectContext.parentContext = self.privateManagedObjectContext
// And instead replace it with this line
// #2
managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator
return managedObjectContext
}()
以下是我使用主要和私有托管对象上下文保存方法的内容。
func save() {
guard managedObjectContext.hasChanges || privateManagedObjectContext.hasChanges else {
return
}
print("Going to save now")
managedObjectContext.performBlockAndWait() {
do {
try self.managedObjectContext.save()
} catch {
fatalError("Error saving main managed object context! \(error)")
}
}
privateManagedObjectContext.performBlock() {
do {
try self.privateManagedObjectContext.save()
} catch {
fatalError("Error saving private managed object context! \(error)")
}
}
}
答案 0 :(得分:1)
private lazy var privateManagedObjectContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
moc.parent = managedObjectContext // Set the receiver’s parent context
return moc
}()
也许这会解决它。
答案 1 :(得分:0)
没有一种正确的方法,但这是我在主线程上更新主要上下文时在后台保存数据的方式。
将主MOC(托管对象上下文)指定为.MainQueueConcurrencyType
。
将您的私人MOC指定为.PrivateQueueConcurrencyType
,将其parentContext
指定为主要MOC。
将私有MOC保存在其后台线程上,然后使用主MOC上的performBlock
方法保存其上下文,这将在主线程上保存主MOC的上下文。 performBlock
确保您使用正确的队列。以下是一个示例,对于它在Objective-C中表示道歉。
在我的设置中,所有更改都始终保存在私有MOC上,然后传播到主MOC。关于核心数据的好书,实际上在objc.io的Swift中,对不同的场景有许多例子和优点/缺点。
// Saving of your private and main context
[[self class] saveContext:self.yourPrivateContext];
[self.yourPrivateContext.parentContext performBlock:^{
[[self class] saveContext:self.yourPrivateContext.parentContext];
}];
+(BOOL)saveContext:(NSManagedObjectContext*)context{
NSError *error = nil;
if (context != nil) {
if ([context hasChanges] && ![context save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
return NO;
}
}
return YES;
}