简体   繁体   中英

Core Data issue. Insert new NSManagedObject

I want to insert 200 5Mb records in my Core Database. But when I save the NSManagedObject, the memory wasn't released (autoreleased pool didn't help), and after inserting 30 records I got the memory warning and the application crashed. Here is my code

- (void)SaveItem
    {
        NSString *entityName = kEntityName;
        AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *context = appDelegate.managedObjectContext;
        NSEntityDescription *entityDesctiption = [NSEntityDescription 
                                                  entityForName: entityName
                                                  inManagedObjectContext:context];
        // check if town exists
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id == %d", self.imageID];
        NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init];
        [requestToCheckExistense setEntity:entityDesctiption];
        [requestToCheckExistense setPredicate:predicate];
        NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil];
        [requestToCheckExistense release];
        if (objects == nil)
        {
            NSLog(@"there was an error");
        }
        NSManagedObject *object;
        if ([objects count] > 0)
        {
            // edit item
            object = [objects objectAtIndex:0];
        }
        else
        {
            // if object doesn't exist, find max id to imlement autoincrement
            NSFetchRequest *request = [[NSFetchRequest alloc] init];
            [request setEntity:entityDesctiption];
            request.propertiesToFetch = [NSArray arrayWithObjects: @"id", nil];
            NSArray *allobjects = [context executeFetchRequest:request error:nil];
            [request release];
            NSInteger newID = 1;
            if ([allobjects count] > 0)
            {
                NSNumber *maxID = [allobjects valueForKeyPath:@"@max.id"];
                newID = [maxID intValue] + 1;
            }

            // write item
            object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; 
            [object setValue:[NSNumber numberWithInt:newID] forKey:@"id"];
            self.imageID = newID;
        }
        // fill NSManagedObject
        // size of objNSData is about 5MB
        NSMutableData *objNSData = [[DatabaseManager sharedDatabaseManager] encryptedDataFromImage:bigImage];
        [object setValue:objNSData forKey:@"big"];

         [context save:nil];
     }

When I commented

[object setValue:objNSData forKey:@"big"];

everything was OK.

I tried to add the code into @autoreleasepool , but that didn't help. I know, that now, when I save data to database, it's still in iPhone RAM. How to release it from this memory? When I get a set of Managed Objects from the database, they are not in the RAM (I can easyly get 100 object, each of them has 5Mb fields)

 object =(tblEntity *) [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];


尝试输入类型转换对象,这可能会解决问题

I've solved the issue. after call of [self SaveItem]; I used

[context save];
[context reset];
[context save];

all the NSManagedObjects from the context will be released. After that operation I can add as many big objects as I want

Because you don't own an NSManagedObject when you create it, it may be retained by the core data stack even after releasing it (when using an autoreleasepool contained inside the loop).

This may help:

  • Set the undo manager of your managedobjectContext to nil:

    [context setUndoManager:nil];

  • Be sure that no properties of that object are retained anywhere, because then the managed object will not be released on time inside your loop.

  • Be sure to add an autorelease pool inside every loop execution, not wrapping all the loop itself, similar to:

     for(i;i<n;i++) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [obj saveItem]; [pool drain]; } 
  • If that object belongs to a hierarchy of NSManagedObjects, then you need to release the owner of this object too, for this one to be deallocated from memory.

You can check apple's documentation about memory management in CoreData.

Warning: big objects (> 1MB) are not recommended by Apple to be stored inside CoreData ( Check this other question/answer. )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM