Search code examples
objective-cexc-bad-accessviewcontrollermultiview

EXEC_BAD_ACCESS when clicking on a button in objective C


I am just learning and trying to put forth some of the knowledge with objective c and cocoa. I have a little program that has a login screen which then displays a main menu. On the main menu view, there is a button that should load a view to be able to add some data to the app. When I click on the button, it doesn't fire the IBAction but throws an error

EXC_BAD_ACCESS [StartMenuViewController performSelector:withObject:]: message sent to deallocated instance 0x6080195e9f90

I know that it is because there is an object that is not instantiated when the message is being sent, but I cannot find out why. Sorry for the code and the novice level here is the main menu view controller StartMenuViewController.m file:

#import "StartMenuViewController.h"
#import "AppDelegate.h"
#import "MasterViewController.h"


@interface StartMenuViewController ()

@end

@implementation StartMenuViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do view setup here.
}


-(IBAction)showStrainView:(id)sender{
    AppDelegate *delegate = nil;
    delegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];

    MasterViewController *addStrainView = [[MasterViewController alloc] initWithNibName:@"MasterViewController" bundle:nil];

    [delegate swapView:self.view toView:addStrainView.view];

}
@end

here is the StartMenuViewController.h

#import <Cocoa/Cocoa.h>

@interface StartMenuViewController : NSViewController
@property (weak) IBOutlet NSButton *showStrainViewButton;

@end

Here is the AppDelegate.h

#import <Cocoa/Cocoa.h>

@class loginView, MasterViewController,StartMenuViewController;


@interface AppDelegate : NSObject <NSApplicationDelegate>{
    loginView *loginView;
    MasterViewController *masterViewController;
}

@property (assign) IBOutlet NSWindow *window;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

@property (strong) loginView *loginView;
@property (strong) MasterViewController *masterViewController;
@property (strong) StartMenuViewController *starMenuViewController;

-(void)swapView:(NSView *)view1 toView:(NSView *)view2;

@end

Here is the AppDelegate.m

#import "AppDelegate.h"
#include "MasterViewController.h"
#import "ScaryBugDoc.h"
#import "Strains.h"
#import "loginView.h"

@interface  AppDelegate()

@end

@implementation AppDelegate

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize loginView;
@synthesize masterViewController;
@synthesize starMenuViewController;


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // 1. Create the master View Controller
    self.loginView = [[loginView alloc] initWithNibName:@"loginView" bundle:nil];

    // 2. Add the view controller to the Window's content view
    [self.window.contentView addSubview:self.loginView.view];
    self.loginView.view.frame = ((NSView*)self.window.contentView).bounds;
}



-(void)swapView:(NSView *)view1 toView:(NSView *)view2{

    //[view1 removeFromSuperview];

    [self.window.contentView addSubview:view2];
    view2.frame = ((NSView*)self.window.contentView).bounds;
}

@end

If you need the loginView.h and loginView.m files I can add them as well. I would appreciate any and all help. Thanks in advance


Solution

  • The problem is here:

    MasterViewController *addStrainView = [[MasterViewController        alloc]initWithNibName:@"MasterViewController" bundle:nil];
    
    [delegate swapView:self.view toView:addStrainView.view];
    

    You don't keep a reference to the MasterViewController so it gets deallocated even though its view is kept around. Now anytime the view tries to access methods from the view controller, things fail.

    You should make addStrainView a child view controller of self in the above code so the view controller sticks around as long as its view.