我将数千个数据插入到我的SQLite存储的Core数据中。 我的ManagedObjectContext的undomanager设置为nil。 我在for循环中插入NSManagedObject。 尝试以两种方式保存上下文,
完成循环后(p循环之外)1。
for(int i =0;i<1000;i++){
MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
object.name = [NSString stringWithFormat:@"%d",i];
object.age = [NSNumber numberWithInt:i];
}
[self managedObjectContext] save:nil];
每次插入2(for循环内部)。
for(int i =0;i<1000;i++){
MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
object.name = [NSString stringWithFormat:@"%d",i];
object.age = [NSNumber numberWithInt:i];
[self managedObjectContext] save:nil];
}
最后我调用了ManagedObjectContext的重置。
[[self managedObjectContext] reset];
但问题是这个过程所占用的内存(插入)在完成后没有回来。
任何人都可以告诉我这是错的,或者这是预期的行为? 避免这种内存泄漏的任何解决方法?
更新
我试过[[self managedObjectContext] refreshObject:object mergeChanges:NO];
它可以放回一些内存,但不能完全。还可以在CoreData
中搜索管理大量数据的良好解决方案。
如果有人建议我在CoreData
处理大量数据的示例项目(源代码),那么对我有帮助。
谢谢。
答案 0 :(得分:2)
我们的项目遇到了同样的问题。重置上下文几乎没有释放任何内存。当在所有父上下文上完成重置时,问题得到解决:
NSManagedObjectContext *currentContext = context;
while (currentContext) {
[currentContext reset];
currentContext = [currentContext parentContext];
}
答案 1 :(得分:1)
这是自动发布池问题的主题。没有authorelease应用程序将保留内存一段时间(只有苹果人知道,多少时间。如果你想在你的手中采取过程,只需更改你的代码:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
for(int i =0;i<1000;i++){
MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
object.name = [NSString stringWithFormat:@"%d",i];
object.age = [NSNumber numberWithInt:i];
[self managedObjectContext] save:nil];
[pool drain], pool = nil;
pool = [[NSAutoreleasePool alloc] init];
}
[pool drain], pool = nil;
答案 2 :(得分:1)
你的代码缺少autoreleasepools:D这意味着你将1000个MyEntity对象存储在内存中,这将导致崩溃,iOS将FC你的应用程序(强制关闭)。代码应如下所示:
for(int i = 0; i < 1000; i++) {
@autoreleasepool {
MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
object.name = [NSString stringWithFormat:@"%d", i];
object.age = [NSNumber numberWithInt:i];
}
}
[self managedObjectContext] save:nil];
OR:
for(int i = 0; i < 1000; i++) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyEntity *object = [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
object.name = [NSString stringWithFormat:@"%d", i];
object.age = [NSNumber numberWithInt:i];
[pool drain];
}
[self managedObjectContext] save:nil];
此外,这可能不是做这种事情的最佳方式,我建议将其添加到上下文中,然后使用
操作上下文本身 [[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];
或类似的东西。这样您就不会创建对象的本地副本并堵塞内存。
使用三种方法中的最后一种,我会这样做:
for(int i = 0; i < 1000; i++) {
[NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] name] = [NSString stringWithFormat:@"%d", i];
[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] age] = [NSNumber numberWithInt:i];
}
[self managedObjectContext] save:nil];
如果此MyEntity是您自己的自定义类,您甚至可以使用
简化代码@property(nonatomic, retain) id name;
@property(nonatomic, retain) id age;
将id name
和id age
替换为正确的变量和对象类,这样您的代码就更简单了:
for(int i = 0; i < 1000; i++) {
[NSEntityDescription insertNewObjectForEntityForName:@"MyEntity" inManagedObjectContext:[self managedObjectContext]];
[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] setName: [NSString stringWithFormat:@"%d", i]];
[[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext] setAge: [NSNumber numberWithInt:i]];
}
[self managedObjectContext] save:nil];
希望这会有所帮助,不会让您感到困惑!
答案 3 :(得分:1)
虽然这有点晚了,
我发现将undo
设置为nil
没有帮助,但以下确实可以防止核心数据泄露。
[[self managedObjectContext] processPendingChanges]; // flush operations
[[[self managedObjectContext] undoManager] disableUndoRegistration]; // disable undo
关于自动释放池。点击异常(包括数字格式例外)object.name = [NSString stringWithFormat:@"%d", i];
您的池将不会根据需要耗尽。事实上,另一个autoreleasepool将耗尽所有自动释放的实例。内存将泄漏,例如通过autorelease创建的异常。所以建议如下。
NSException *myexception = nil;
try {
.... [yadda yadda];
} catch (NSException e)
{
myexception = [e retain];
@throw;
}
finally {
[pool drain];
[myexception release];
}
我建议不要放入autoreleasepool,理清[[[self managedObjectContext] undoManager] disableUndoRegistration];
是否有助于较小的集合然后移动更大。核心数据中的撤销管理器是一个漏洞,我还没有想出解决方案。