2

I'm currently parsing all of my data from JSON and storing it in an array. However when it starts parsing the memory usage jumps up from about 25mb to 800mb. After doing some research I was told to put an @autoreleasepool in the GCD block but to no avail.

Here's the code I've got so far:

 self.channelSchedules = [NSMutableArray new];
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Add code here to do background processing
    //Loop through each channel object and download schedule
    @autoreleasepool {
        for (atlas_channel* channel in self.channels) {
            NSLog(@"Updating listings for %@", [channel getChannelTitle]);
            [self.channelSchedules addObject:[[channel getChannelSchedule] returnCurrentContentObject]];
            [self.tableView reloadData];
            [self scrollViewDidScroll:nil];
        }
    }
    dispatch_async( dispatch_get_main_queue(), ^{
        // Add code here to update the UI/send notifications based on the
        // results of the background processing
        [self.tableView reloadData];
    });
});

I'm using TouchJSON to parse the data.

Upon further research I think this has something to do with the fact that I'm storing all values once parsed into an NSArray which retains each object in memory. I'm thinking I'll have to use CoreData or something along those lines.

Kieran Crown
  • 93
  • 1
  • 11
  • If your autoreleasepool is inside the for loop you will get a drain at every iteration. There might be better ways to design this code to avoid memory, but that might be a quick fix. – KirkSpaziani Jul 28 '15 at 19:00
  • It has halved it to about 400mb. That still seems pretty high though – Kieran Crown Jul 28 '15 at 20:42
  • 1
    how much data are you parsing? @autoreleasepool is useless here (isn't your entire app under @autoreleasepool?) – Ali Jul 29 '15 at 08:30
  • I'm parsing one JSON file and then for each entry returned I have to parse another two JSON files. This is because of the way atlas works. I'm using the Atlas API from metabroadcast. – Kieran Crown Jul 29 '15 at 08:35

3 Answers3

2

Only call [self.tableView reloadData] on the mainThread.

I make my mark
  • 841
  • 6
  • 13
2
  1. Are you accessing the same mutable array from two threads simultaneously? That won't work reliably.

  2. As someone else said, don't update the table from a background thread.

  3. How big are the JSON files? You are essentially storing all of the data in RAM in a less efficient way, so expect twice the memory usage as the raw text.

  4. Try Apple's JSON parser.

EricS
  • 9,650
  • 2
  • 38
  • 34
  • 1. Yes I am although I'm considering switching from using an Array to Core Data or something similar. 2. I have removed that now. 3. Each JSON file is about 0.14mb which is hardly anything but I've got to download about 400-450 of these files. 4. I was using Apple's JSON parser at first but it crashed every time there was a nil object so I switched. – Kieran Crown Jul 29 '15 at 13:44
  • 1
    Unless you need all of the decoded data at once, you might be better off just storing the 400 files in your Documents or Cache directory and decoding them as you need them. – EricS Jul 29 '15 at 16:33
  • That's what I'm currently doing now. I'm going to be storing the data using Core Data. I'll report back on how it goes. – Kieran Crown Jul 30 '15 at 09:24
1

The high memory usage was because I was storing the JSON items in an NSArray which retains itself in memory. I was able to work around this by using realm to cache my objects to disk and call them when needed like EricS suggested. The app now uses 32mb at most which is much better.

Kieran Crown
  • 93
  • 1
  • 11