Frage

I am writing an application where the user should be able to click on a button and have the views switch. I have created IBActions that load my method switchSubView on the desired view, but have been having some issues in doing so. I have currently written methods to animate the transition between two NSViews connected through Interface Builder as IBOutlets. I am able to use the methods to transition between two views, but when I try to switch from the initial view to another view, then switch to another, and then switch back, I get EXC_BAD_ACCESS. I can't seem to debug the problem. The debugger shows both of the NSView objects to point to distinct memory locations. To clarify, I would like to reuse the views throughout the duration of the application's execution. I would not like any of the views to be deallocated.

Here is the code:

- (void)switchSubViews:(NSView *)firstView withView:(NSView *)secondView {
    [firstView setSubviews:[NSArray array]];
    [self prepareViews:firstView];
    [[firstView animator] addSubview:secondView];
}

/* Make a "move" animation effect. */
- (void)prepareViews:(NSView *)prepareView {
    CATransition * transition = [CATransition animation];
    [transition setType:kCATransitionPush];
    [transition setSubtype:kCATransitionFromRight];
    [prepareView setAnimations:[NSDictionary dictionaryWithObject:transition forKey:@"subviews"]];
    [prepareView setWantsLayer:YES];
}

Basically, I would call it like this, given initialView and newView:

[self switchSubViews:initialView withView:newView];

Can anyone help me debug this?

Thanks.

Update: After commenting out the for loop and the removeFromSuperview code to debug, I am still receiving the bad access error. The properties for the view are set to @property (nonatomic, strong), so shouldn't the views be retained? If not, how can I explicitly retain my NSView(s) with ARC enabled? Is it possible to tell ARC to retain it, or is it already retaining the view since it is set with @property(nonatomic, strong)?

Second Update: I researched a little and found out that I can cause ARC to retain the object by creating a strong pointer to the object. I tried it by creating instance variables:

@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate> {
    /* Some instance variables here... */
    __strong NSView * retainFirstView;
    __strong NSView * retainSecondView;
}

@property (nonatomic, strong) NSView * retainFirstView;
@property (nonatomic, strong) NSView * retainSecondView;

And then in the .m file:

#import <Quartz/Quartz.h> /* Animation. */
#import "AppDelegate.h"
/* Some other imports necessary... */

@implementation AppDelegate

@synthesize retainFirstView;
@synthesize retainSecondView; 

/* Some subview switching code... */
[self setRetainFirstView:firstView];
[self setRetainSecondView:secondView];

@end

but I still receive the error. It seems that the view that I am swapping out is consistently being deallocated. I've spent significant time on this and haven't been able to get rid of the error. Any help would be appreciated. If this isn't the proper way to retain the view, please let me know.

Update 3: To test, I have disabled ARC temporarily and did this before calling setSubviews or addSubview:

[firstView retain]; 
[secondView retain];

and it still failed. I am quite confused, as I no longer see what could be causing the deallocation.

Update 4: I checked for zombies and messages sent to deallocated objects by doing Product -> Profile in Xcode, and to my surprise, I wasn't notified of any. I am very confused on why this is occurring.

War es hilfreich?

Lösung

You're getting EXC_BAD_ACCESS because calling -removeFromSuperview will deallocate that view if nothing else is retaining it. It's very likely that a view that is being deallocated (therefore having an object pointer that points to garbage) is later passed into -switchSubviews:withView, causing your crash. You should always retain views that you are going to be using later on before calling -removeFromSuperview to make sure that they are not deallocated.

As a sidenote, the code for -switchSubviews:withView: is needlessly complicated. It could be reduced to this:

- (void)switchSubViews:(NSView *)firstView withView:(NSView *)secondView {
    firstView.subviews = [NSArray array];
    [self prepareViews:firstView];
    [[firstView animator] addSubview:secondView];
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top