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".
@Alexart answer worked for me but if you want a simplified version, use
+(instancetype)reachabilityWithAddress:(void *)hostAddress
{
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
if (ref)
{
id reachability = [[self alloc] initWithReachabilityRef:CFBridgingRetain((__bridge id)ref)];
CFRelease(ref);
return reachability;
}
return nil;
}
I think better to do it next way:
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
{
Reachability* retVal = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if(reachability!= NULL)
{
retVal= [[self alloc] init];
if(retVal!= NULL)
{
retVal->reachabilityRef = reachability;
retVal->localWiFiRef = NO;
}
else
{
CFRelease(reachability);
}
}
return retVal;
}
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.
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