0

The first time a user opens my app I need to download lots of data. I get all of this data from the server in JSON form. Depending on the user, these JSON files can be anywhere from 10kb - 30mb each, and there are 10+ of them.

I have no problems doing this when the JSONs have no more than 500 or so records, but like I said some have 10,000+ records and can be up to 30mb in size.

When downloading the larger JSONs, my app allocs a ton of memory, until I eventually get memory warnings and the app blows up.

It seems the CFData has to be the NSMutableData that I am building in didReceiveData. As I download a single JSON the CFData (store) rises-- and when I begin parsing it stops rising.

How can I clear out that data before moving on to download & parse the next JSON?

As you can see below, there is 200mb of CFData (store) sitting around in memory:

enter image description here

--

Digging into the CFData doesn't reveal much to help me: enter image description here

Here is the code where I create operations to get these various JSONs--

- (void)checkForUpdates
{
    if(!_globals)
        _globals = [MySingleton sharedInstance];

    MyAFHTTPClient* client = [MyAFHTTPClient sharedClient];
    NSString* path = [NSString stringWithFormat:@"cache?deviceUID=%@&token=%@",[_globals getMacAddress], [_globals getToken]];
    NSURLRequest* request = [client requestWithMethod:@"GET" path:path parameters:nil];

     _currentEnvironment = [_globals getActiveEnvironment];       

    if(!_currentEnvironment.didDownloadDataValue)
        [self setupAndShowHUDinView:self.view withText:@"Checking for updates..."];

    AFJSONRequestOperation* operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

        for(NSString *str in [JSON valueForKey:@"Views"])
        {
            //for each table i need to update, create a request to
            NSString* path = [NSString stringWithFormat:@"cache/%@/?deviceUID=%@&token=%@", str, @"00000-00000-0000-00001", [_globals getToken]];
            NSURLRequest* request = [client requestWithMethod:@"GET" path:path parameters:nil];
            AFJSONRequestOperation* operation2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) 
            {
                    // even if this is comment this out and I do nothing but download, app crashes
                    //[self updateTable:str withJSON:JSON];
            } failure:nil];

            [operation2 setSuccessCallbackQueue:backgroundQueue];
            [client.operationQueue addOperation:operation2];
            numRequests++;
        }
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {

    }];

    [operation start];
}

Is that CFData my JSONs responses that are in memory? I have attempted to clear my NSURLCache with no luck--

I have also looked a little into JSON streaming.. would that help me at all to reduce the amount of objects in memory?

Besides that the only other option I can think of is implementing some sort of paging..but I need my users to have all of the data

Any help/suggestions is greatly appreciated! Thanks!

--

EDIT

Ok I decided to use strip out AFNetworking and try to use native functions. In doing this I still get the same build of of CFData. I am using this subclass of NSOperation and I am creating/ adding my operations as follows now:

 NSOperationQueue *operationQueue;
 operationQueue = [[NSOperationQueue alloc]init];
 [operationQueue setMaxConcurrentOperationCount:1];
 for(NSString *str in [views valueForKey:@"Views"])
 {

     NSString* path = [NSString stringWithFormat:@"%@cache/%@/?deviceUID=%@&token=%@", _globals.baseURL, str, @"00000-00000-0000-00001", [_globals getToken]];

     LibSyncOperation *libSyncOperation = [[LibSyncOperation alloc] initWithURL:path];
     [operationQueue addOperation:libSyncOperation];

 }
RyanG
  • 4,393
  • 2
  • 39
  • 64

1 Answers1

2

I use the native JSON conversion functions with massive amounts of data with no memory problems.

I just use a standard NSURLConnection to download the NSData then do the following...

NSData *data = [NSURLConnection sendSynchronous...

// use NSDictionary or NSArray here
NSArray *array = [NSJSONSerialization JSONObjectWithData:data ...

Now deal with the objects.

No leaks as it's a native function. A lot quicker than third parts frameworks.

Fogmeister
  • 76,236
  • 42
  • 207
  • 306
  • Yeah I was thinking about not using AFNetworking and going native.. but I thought that someone may have accomplished what I am trying to do with AFNetworking (and honestly i figured using AFNetworking would be better than me trying to code it all completely). Ill give this a go tomorrow-- – RyanG Jan 31 '13 at 21:57
  • I added some new info & code to my question above.. I am still seeing the issue even when not using AFNetworking. – RyanG Feb 01 '13 at 15:10
  • OK, I've had a look at your NSOperation and TBH I'm not 100% certain what is going on. What is extremely useful though is the Static Analyser built into XCode. Especially in finding leaks in static memory allocations (especially in Core Foundation objects like CFData). Give it a try. Instead of hitting "Run" press and hold and select "Analyze". – Fogmeister Feb 03 '13 at 22:08
  • I ended up first downloading the JSON files to disk-- which I did without using AFNetworking and it is working good and not leaking like it was. – RyanG Feb 04 '13 at 13:54