Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reachability Classes crashing program - not sure why

I have an 'internet aware' base class for objects which require networking in my app. All the objects which need to be internet aware inherit from it. As you can imagine I allocate and deallocate a lot of these objects.

The internet aware base class has the following code to interact with the Reachability classes used to check for internet status.

#import "Reachability.h"

- (id) init {
    ...
    self.internetReachable = [Reachability reachabilityForInternetConnection];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus) name:kReachabilityChangedNotification object:nil];
    [self.internetReachable startNotifier];
    ...
  }
- (void)  dealloc
 {
    [self.internetReachable stopNotifier];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
 }

As soon as there is a change in internet status in my app, the app crashes with the following error:

*** -[Reachability isKindOfClass:]: message sent to deallocated instance 0x1e249a30

Ive turned on zombies and tracked the problem down to the following line of code within Reachability.m

NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");

Unfortunately, beyond stopping listening for NSNotifcations and stopping the notifier, im not sure what else my objects can do to avoid this error.

Any help or suggestions would be great.

Thanks

Vb

Edit:

OK so following the advice of the answer below I ran it in instruments with allocations and this was the retain count history.

enter image description here

It is as I suspected, its an object that I have deallocated being called by Foundation (ie. NSNotifcationCenter) and not myself.

My internet objects have a strong pointer to a Reachability object. When they are deallocated, so is the Reachability object. The zombie is the Reachability object. In the dealloc of my internet object I have called removeObserver, but foundation is still calling the deallocated object. I can't understand why...

like image 245
BYZZav Avatar asked Mar 21 '13 17:03

BYZZav


2 Answers

The reason that Foundation was still sending the deallocated Reachability the NSNotifcations was because the Reachability object was being deallocated on a different thread to the one it was being created on ie. Reachability isn't thread safe. Using dispatch_async back to the same queue that the Reachability object was being created on has solved the problem.

like image 86
BYZZav Avatar answered Nov 03 '22 08:11

BYZZav


This happens when the object you made that instantiates Reachability, and hence holds a reference to a Reachability instance, is deallocate without (or before) you call stopNotifier on it!

Solving this is very simple. You must call stopNotifier before your object gets removed from the stack tearing down your Reachability instance with it. You can do this in the dealloc method, or if it's a viewController, you could call it in one of the lifecycle methods such as viewDidDisappear, etc.

There should be no need of messing with threads here. Consider, when you call startNotifier on Reachability this thing starts on a background thread by design of Reachability. So, when you call stopNotifier it takes care of threading for you.

The reason you're having to mess with threads has to do with the fact that your object holding the reference to Reachability got deallocated but was still a registered listener for network changes, which happened with startNotifier. When the network does change, guess what, your object, although still registered to receive notifications, is nowhere to be found! Crashy crash. stopNotifier unregisters it before it dies and everything is good.

- (void)dealloc
{ // self.hostReachability is my property holding my Reachability instance
    if (self.hostReachability) {
        [self.hostReachability stopNotifier];
    }
}
like image 25
smileBot Avatar answered Nov 03 '22 09:11

smileBot