0

I have many objects in NSMutableArray(>2500) and when I save it, app crashes (received memory warning x3).

    NSLog(@"start");
    NSInteger saveTemp = 0;
    NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&err];
    if ([data length] > 0 && err == nil)
    {
        MyClass* rcust;
        NSString *respStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSMutableArray* cust = [respStr JSONValue];
        for(NSDictionary *v in cust)
        {
            if([dataProvider getClassById:[[v valueForKey:@"Id"] integerValue] error:nil] == nil)
            {
                rcust = [dataProvider createClass];
                rcust.clsId = [v valueForKey:@"Id"];
            }
            else
            {
                rcust = [dataProvider getClassById:[[v valueForKey:@"Id"] integerValue] error:nil];
            }
            rcust.cstZip = [v valueForKey:@"Zip"] == [NSNull null]? @"": [v valueForKey:@"Zip"];

            saveTemp++;
            if(saveTemp > 1000)
            {
                NSLog(@"save");
               [dataProvider saveContext];
                saveTemp = 0;
            }
        }
        [dataProvider saveContext];
    }

Here the saveContext method

- (void)saveContext {
    NSError*err = nil;
    if(![[self managedObjectContext] save:&err])
    {
        NSLog(@"Unresolved error %@, %@", err, [err userInfo]);
    }
}

UPDATE: I added code to the method and there you are.

2013-03-21 15:18:54.641  start
2013-03-21 15:19:31.843  save
2013-03-21 15:23:21.126  save

i.e. Data saving is getting slower and after a while, the application crashes.

Yury Lego
  • 21
  • 1
  • 5

1 Answers1

0

So it looks like you have >2500 customers being returned from that NSURLRequest. By the time you've populated the cust array, you have four copies of that data (as NSData, as NSString, as NSMutableArray, and in your NSManagedObjectContext).

Use @autoreleasepool to wrap your NSData and NSString conversions. Once you have done your -JSONValue call, you don't need those representations anymore.

Then, wrap your processing loop in an @autoreleasepool also. That will allow intermediate results (even the ones you can't see) to be freed.

Finally, when you do your saveContext, do a -reset on the managed object context too.

Two other notes for you:

Your check of the NSError parameter in line 4 is incorrect. For methods that have an NSError** parameter, the NSError return value is undefined if the operation succeeds. The logic should be if (data.length > 0) then proceed, otherwise examine NSError. See NSURLConnection's class reference.

Also, your getClassById method appears to violate Cocoa naming standards. If the method begins with the word get, it must return its results by reference in parameters. See https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html#//apple_ref/doc/uid/20001282-BCIGIJJF.

Hal Mueller
  • 7,019
  • 2
  • 24
  • 42
  • Thanks. It solved a problem with leakage of memory. But all the same in a cycle preservation goes all more slowly and more slowly. How I can accelerate process of saving of data? – Yury Lego Mar 29 '13 at 16:54
  • Is it actually the `saveContext` call that is slow? Or some other part? This would be a good time to fire up Instruments, and to turn on `com.apple.CoreData.SQLDebug` (see http://useyourloaf.com/blog/2010/03/11/debugging-core-data-on-the-iphone.html). I notice that your misnamed `getClassById:error` is called twice for some iterations. What does it do? – Hal Mueller Mar 29 '13 at 18:50