christopher
christopher

Reputation: 520

AFNetworking CFData Leak?

I am having a problem with AFNetworking. I am requesting a lot of JSON data from my Server via GET using this:

[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:@{...} success:^(AFHTTPRequestOperation *operation, id JSON) {

    [_delegate receivedRateResponse:JSON];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [_delegate receivedRateResponse:nil];
}];

When this is called around 10-20 times, CFData seems to take most of the used memory of my app.

Memory Usage

memory used

When I investigate both CFData and CFData (store), I get the following:

CFData (store)

CFData store memory

CFData

CFData memory

Side note: My app is using ARC and everything else seems to perform fine.

My question is now, as I didn't see any pending issues on AFNetworking's GitHub Page and almost no other complaints about that on the internet, what the heck am I doing wrong? Is anybody else facing this issue or am I the only one? Could you please post your code, as I don't think my Code looks that wrongs...

Update 1

The code for interface:

@protocol RateRequestsDelegate;

@interface RateRequests : NSObject  {
   id<RateRequestsDelegate>  _delegate;
}
@property (nonatomic, strong) id<RateRequestsDelegate> delegate;
- (void)fetchRateList;
@end

@protocol RateRequestsDelegate <NSObject>
- (void)receivedRateResponse:(NSDictionary *)response;
@end

SessionResponseClient is just an extended AFHtttpClient instance, as all the AFNetworking examples demonstrate, see: Interact with an API

The code for receivedRateResponse:

- (void)receivedRateResponse:(NSDictionary *)json {
  if (!json)    {
    return;
  }

  self.moviesToInsert = [NSMutableArray arrayWithArray:[json objectForKey:@"rated"]];

  [self.tableView reloadData];
}

Update 2

I changed the callback now to a block-based function instead of using delegates and it improved a little, but its barely mentionable and could also be caused by just a side effect of something else. How do you guys implement this? Try fetching data, display it in a table- or scrollview and then pull these data many times from the server and refresh the views

Many thanks! Paul

Upvotes: 3

Views: 1421

Answers (3)

srjohnhuang
srjohnhuang

Reputation: 342

Maybe you could give @autoreleasepool a try. For example:

@autoreleasepool {

// your codes below
[[SessionResponseClient sharedClient] getPath:kURIRateList parameters:@{...} success:^(AFHTTPRequestOperation *operation, id JSON) {

    [_delegate receivedRateResponse:JSON];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [_delegate receivedRateResponse:nil];
}];
// your codes above

}

Upvotes: 0

larromba
larromba

Reputation: 306

Thanks dude - I had the exact same problem - your solution worked.

However, I thought I'd comment that in your solution, you're essentially turning the NSURLCache off once you receive a memory warning. I'm not sure exactly how AFNetworking uses the NSURLCache, but I'm assuming their implementation won't work as effectively if you turn it off (i.e. by setting its capacity to 0). This may slow down the request speed after your first memory warning onwards. As an extreme edge case, you might even experience unexpected behaviour after a few days of using your app, as it might not manifest until the first memory warning.

I instead suggest implementing something that removes the cached responses, but keeps the cache active:

-(void)didReceiveMemoryWarning
{
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
}

The only issue is that AFNetworking may need to build up its cache again, but I'm assuming this won't affect the framework quite as much.

Lastly, just in case it's useful to you or anyone - in order to register your own method to a memory warning notification, you can do this:

[[NSNotificationCenter defaultCenter] addObserver:self (or pointer to your singleton)
                                         selector:@selector(myMethod)
                                             name:UIApplicationDidReceiveMemoryWarningNotification
                                           object:nil];

I hope that helps!

Upvotes: 2

christopher
christopher

Reputation: 520

Okay, the solution was that CFData (store) seems to be responsible for holding the url cache in memory when using NSURLConnection's.

So all I had to do was call...

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

...to clear the cache, once I received a memory warning...

Or you can just call it whenever you want(didn't time profile that function though)...

Hope this helps someone who encounters a similar problem.

Upvotes: 1

Related Questions