After posting this as an issue to the AFNetworking repo, turns out this is in fact a usage issue on my part. Per the response to my issue:
NSURLSession retains its delegate (i.e. AFURLSessionManager). Call invalidateSessionCancelingTasks: to ensure that sessions finalize and release their delegate.
So, long story short: If you are using AHTTPSessionManager
in the manner described below, make sure to call invalidateSessionCancelingTasks:
to ensure that sessions finalize and release their delegate
I have a subclassed AFHTTPSessionManager
called GTAPIClient
that I am using to connect to my REST API. I realize the docs state to use as a singleton but there are a few cases where I need to gin up a new instance. However, it seems that whenever I do so, the object is never deallocated. Currently, GTAPIClient
literally does nothing except NSLog
itself when deallocated.
Here's some sample code that demonstrates the behavior
@implementation GTAPIClient
- (void)dealloc
{
NSLog(@"Dealloc: %@", self);
}
@end
#import "GTBaseEntityViewController.h"
//Models
#import "GTBaseEntity.h"
//Clients
#import "GTAPIClient.h"
@interface GTBaseEntityViewController ()
@property (nonatomic, weak) GTAPIClient *client;
@property (nonatomic, weak) GTBaseEntity *weakEntity;
@end
@implementation GTBaseEntityViewController
- (IBAction)makeClient:(id)sender {
self.client = [[GTAPIClient alloc] init];
NSLog(@"I just made an API client %@", self.client);
//Another random object assigned to a similar property, just to see what happens.
self.weakEntity = [[GTBaseEntity alloc] init];
NSLog(@"I just made a random object %@", self.weakEntity);
}
- (IBAction)checkClient:(id)sender {
NSLog(@"Client: %@", self.client);
NSLog(@"Entity: %@", self.weakEntity);
}
@end
Fire makeClient:
//It seems to me that both NSLog's should return (null) as they are assigning to a weak property
2014-06-22 16:41:39.143 I just made an API client <GTAPIClient: 0x10b913680, baseURL: (null), session: <__NSCFURLSession: 0x10b915010>, operationQueue: <NSOperationQueue: 0x10b9148a0>{name = 'NSOperationQueue 0x10b9148a0'}>
2014-06-22 16:41:39.144 I just made a random object (null)
Fire checkClient
//Again, both NSLog's should return null for the two objects. However...client is still around. Also, it's overridden dealloc method never fired.
2014-06-22 16:44:43.722 Client: <GTAPIClient: 0x10b913680, baseURL: (null), session: <__NSCFURLSession: 0x10b915010>, operationQueue: <NSOperationQueue: 0x10b9148a0>{name = 'NSOperationQueue 0x10b9148a0'}>
2014-06-22 16:44:43.723 Entity: (null)
For reference, I am using v2.3.1 of AFNetworking. Compiler is warning me that assigning retained object to weak property will release after assignment - which is correct, and functions as expects with my random object. There is nothing else going on in the app. No other view controllers, no other methods on the GTAPIClient
, all singleton functionality is removed. Any thoughts on what I am doing wrong here?
Posting the response from Mattt Thompson here to assist future readers:
NSURLSession
retains its delegate (i.e.AFURLSessionManager
). CallinvalidateSessionCancelingTasks:
to ensure that sessions finalize and release their delegate.
If, like many apps, your app uses a singleton Session Manager and one URL Session for your entire app, then you don't need to worry about this.
Replicating your scenario and running it through Instruments shows that AFURLSessionManagers are retained by the NSURLSessions they create, as AFURLSessionManager acts as the delegate for every NSURLSession created. This creates a retain cycle and thus the AFHTTPSessionManager cannot be released. Whether this is a bug in either library or not a bug at all, I'm not sure. You may want to report it on the AFNetworking GitHub page (https://github.com/AFNetworking/AFNetworking).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With