简体   繁体   中英

Create NSManagedObject (big size). Memory warning and the application crashes

I'm a new iOS developer. Hope for help. I want to be able to create many NSManagedObjects. The size of fields of one NSManagedObject is about 5Mb. I couldn't save such a big amount of memory in the iPhone memory. And I want to save it in the database. But when I save the NSManagedObject, it's still in the memory, because when I save about 20 objects, I get the memory warning and the application crashes. 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 try to call [self SaveItem] 20 times , the app crashes with memory warning. When I commented

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

everything was OK.

I tried to add the code to @autoreleasepool , but that didn't help.

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

Storing images (or big binary values) in core data is not a good option. Apple recommends against it. There are rules for that. Check this other question/answer.

If you want to get the objects out of memory, you need to remove all references you have for them. If you are executing "SaveItem" in a tight loop, you should wrap every loop execution in an autorelease pool, not the loop itself.

From apple docs, that may be your problem too:

Managed objects that have pending changes (insertions, deletions, or updates) are retained by their context until their context is sent a save:, reset , rollback, or dealloc message, or the appropriate number of undos to undo the change. The undo manager associated with a context retains any changed managed objects. By default, the context's undo manager keeps an unlimited undo/redo stack. To limit your application's memory footprint, you should make sure that you scrub (using removeAllActions) the context's undo stack as and when appropriate. Unless you retain a context's undo manager, it is deallocated with its context.

If you do not intend to use Core Data's undo functionality, you can reduce your application's resource requirements by setting the context's undo manager to nil. This may be especially beneficial for background worker threads, as well as for large import or batch operations.

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