Search code examples
objective-coverridingnsnotificationcentersubclassingnsnotification

Adding NSNotification cause app crash


I have two classes one is base class and the other is subclass. In the base class i am adding a notification that will be fired when the app goes to the background. But some how the app crashes after executing the handleAppBackground method. I guess it has to do some thing with the subclass instance because when i remove the subclass instance from appDelegate, then it does not crash.

#import <Foundation/Foundation.h>

@interface BaseClass : NSObject

+(BaseClass *) sharedManager;
- (void) handleAppBackground;

@end

implementation files is

#import "BaseClass.h"

@implementation BaseClass
- (instancetype) init{
    if(self = [super init]){
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];

    }
    return self;
}

+(BaseClass *) sharedManager{
    static BaseClass *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[BaseClass alloc] init];

    });
    return sharedInstance;
}
- (void) handleAppBackground{
    NSLog(@"Here");

}
@end

The SubClass is header is

#import <Foundation/Foundation.h>
#import "BaseClass.h"

@interface SubClass1 : BaseClass
-(SubClass1 *) init;
-(void) method1;
@end

and the implementation is

#import "SubClass1.h"

    @implementation SubClass1

    -(SubClass1 *) init{
        if(self = [super init]){

        }
        return self;
    }


    -(void) method1{
        NSLog(@"Called in SubClass1");
    }
    @end

and in the appDidFinnishLaunching

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    [BaseClass sharedManager];
    SubClass1 *class1 = [[SubClass1 alloc] init];
    [class1 method1];
    // Override point for customization after application launch.
    return YES;
}

Here is the crash log any help please

 thread #1: tid = 0x31435, 0x015740e6 libobjc.A.dylib`lookUpImpOrForward + 59, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x0)
    frame #0: 0x015740e6 libobjc.A.dylib`lookUpImpOrForward + 59
    frame #1: 0x0157405c libobjc.A.dylib`lookUpImpOrNil + 62
    frame #2: 0x0156b84a libobjc.A.dylib`class_respondsToSelector_inst + 65
    frame #3: 0x0156b801 libobjc.A.dylib`class_respondsToSelector + 32
    frame #4: 0x017dd4cb CoreFoundation`___forwarding___ + 955
    frame #5: 0x017dd0ee CoreFoundation`__forwarding_prep_0___ + 14
    frame #6: 0x0123f049 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    frame #7: 0x01848f04 CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    frame #8: 0x017a0efb CoreFoundation`_CFXNotificationPost + 2859
    frame #9: 0x01178e41 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 98
    frame #10: 0x002334b3 UIKit`-[UIApplication _handleApplicationSuspend:eventInfo:] + 817
    frame #11: 0x00240193 UIKit`-[UIApplication handleEvent:withNewEvent:] + 4030
    frame #12: 0x00240555 UIKit`-[UIApplication sendEvent:] + 85
    frame #13: 0x0022d250 UIKit`_UIApplicationHandleEvent + 683
    frame #14: 0x037e2f02 GraphicsServices`_PurpleEventCallback + 776
    frame #15: 0x037e2a0d GraphicsServices`PurpleEventCallback + 46
    frame #16: 0x01768ca5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
    frame #17: 0x017689db CoreFoundation`__CFRunLoopDoSource1 + 523
    frame #18: 0x0179368c CoreFoundation`__CFRunLoopRun + 2156
    frame #19: 0x017929d3 CoreFoundation`CFRunLoopRunSpecific + 467
    frame #20: 0x017927eb CoreFoundation`CFRunLoopRunInMode + 123
    frame #21: 0x037e15ee GraphicsServices`GSEventRunModal + 192
    frame #22: 0x037e142b GraphicsServices`GSEventRun + 104
    frame #23: 0x0022cf9b UIKit`UIApplicationMain + 1225
  * frame #24: 0x00002a2d TestSubclass`main(argc=1, argv=0xbfffed60) + 141 at main.m:16

Solution

  • It looks like your app crashes because it can't find the selector which you assigning to the notification.

    In your case, what caused it, is that you didn't set the class object of SubClass1 as the iVar of AppDelegate .

    SubClass1 *class1

    So the object is being released after didFinishLaunchingWithOptions method, and when the app goes to background, the observer cannot find the selector due to the object being deallocated.

    In your example if you change your AppDelegae.m code to

    @interface AppDelegate()
    {
        SubClass1 *class1;
    }
    @end
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [BaseClass sharedManager];
        class1 = [[SubClass1 alloc] init];
        [class1 method1];
    
    .......
    }
    

    and don't forget to remove observer when SubClass1 being deallocated

    SubClass1.m
    -(void)dealloc {
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
    

    So it's basically a memory issue.