Maria Maria - 20 days ago 9
iOS Question

Apple's reachability memory leak

I use apple's Reachabiliry class in my non-arc project. And when I run it with instruments to find memory leaks, it referes to Reachability method. Here is the problem:

+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);

WReachability* returnValue = NULL;

if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->reachabilityRef = reachability;
returnValue->localWiFiRef = NO;
}
}
return returnValue;
}


The leaked objects are reachability and returnValue.
I understand that SCNetworkReachabilityCreateWithAddress creates a new instance and I must CFRelease it, but it happens right in dealloc!

- (void)dealloc
{
[self stopNotifier];
if (reachabilityRef != NULL)
{
CFRelease(reachabilityRef);
}
[super dealloc];
}


So what can I do to avoid memory leak here?

UPD:
Maybe the problem is in how reachability get called? I use this method:

+ (instancetype)reachabilityForInternetConnection;
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;

return [self reachabilityWithAddress:&zeroAddress];
}


Then I called Reachability like this:

[[Reachability reachabilityForInternetConnection] startNotifier];


And don't assign it to any object, just use this line.
I've tried to change this calls to something like:

Reachability *reachability = [[Reachability reachabilityForInternetConnection] autorelease];
[reachability startNotifier];


But after this analyzer told me "too many autorelease".

Answer

If returnValue equals to NULL reachability object is leaked, you should release it in this case. Also by Cocoa naming convention (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1) you must return autoreleased object:

+ (instancetype)reachabilityWithAddress:
{
    ...
     returnValue = [[[self alloc] init] autorelease];

Or rename the method to start for example from new: newReachabilityWithAddress or something like this if you don't want to return an autoreleased object.

Try to run static analyser in Xcode, it can help to spot the problems.

Comments