使用iPhone SDK UINavigationController的EXC_BAD_ACCESS

时间:2010-08-13 16:23:50

标签: iphone xcode sdk uinavigationcontroller exc-bad-access

好吧所以我试图在Xcode中使用一个简单的UINavigationController和iPhone SDK,它在推送时效果很好但是如果经过2次推送并尝试弹出视图控制器我会不断收到错误:EXC_BAD_ACCESS

我知道这意味着什么,但我该怎么办呢?

这是我的代码...(假设MainViewController有一个调用函数showStartMenu的按钮)

FurballAppDelegate.h

//
// FurballAppDelegate.h
// Furball
//
// Created by Morgan Family on 7/28/10.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import <UIKit/UIKit.h>

@class MainViewController, StartViewController, SubjectViewController;

@interface FurballAppDelegate : NSObject <UIApplicationDelegate> {
 UIWindow *window;
 UINavigationController *navController;
 MainViewController *mainController;
 StartViewController *startController;
}

@property (nonatomic, retain) UIWindow    *window;
@property (nonatomic, retain) UINavigationController  *navController;
@property (nonatomic, retain) MainViewController  *mainController;
@property (nonatomic, retain) StartViewController  *startController;

- (void)popBack;
- (void)pushNext:(UIViewController *)next;
- (void)showStartMenu;

@end

FurballAppDelegate.m

//
// FurballAppDelegate.m
// Furball
//
// Created by Morgan Family on 7/28/10.
// Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import "FurballAppDelegate.h"

#import "MainViewController.h"
#import "StartViewController.h"
#import "SubjectViewController.h"


@implementation FurballAppDelegate

@synthesize window;
@synthesize navController;
@synthesize mainController;
@synthesize startController;


- (void)applicationDidFinishLaunching:(UIApplication *)application {

 window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

 mainController = [[MainViewController alloc] init];

 navController = [[UINavigationController alloc] initWithRootViewController:mainController];

 [window addSubview:navController.view];

 [window makeKeyAndVisible];

}


- (void)dealloc {

 [mainController release];
 [startController release];
 [subjectController release];

 [window release];
 [super dealloc];

}


- (void)popBack {
 [navController popViewControllerAnimated:YES];
}


- (void)pushNext:(UIViewController *)next {
 [navController pushViewController:next animated:YES];
}


- (void)showStartMenu {
 startController = [[StartViewController alloc] init];
 [self pushNext:startController];
}


@end

StartViewController.h


//
// StartViewController.h
// Furball
//
// Created by Morgan Family on 8/4/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import 

@interface StartViewController : UIViewController {

}

- (void)showSubjectMenu;

@end

StartViewController.m

//
// StartViewController.m
// Furball
//
// Created by Morgan Family on 8/4/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "FurballAppDelegate.h"
#import "StartViewController.h"
#import "SubjectViewController.h"

@implementation StartViewController


- (void)loadView {

 UIView *view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];

 UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
 [btn setFrame:CGRectMake(50, 50, 100, 30)];
 [btn setTitle:@"DO WORK" forState:UIControlStateNormal];
 [btn addTarget:self action:@selector(chooseSubject) forControlEvents:UIControlEventTouchUpInside];

 [view addSubview:btn];

 FurballAppDelegate *app = [[UIApplication sharedApplication] delegate];

 UIButton *btnBack = [UIButton buttonWithType:UIButtonTypeRoundedRect];
 [btnBack setFrame:CGRectMake(50, 100, 100, 30)];
 [btnBack setTitle:@"DO WORK" forState:UIControlStateNormal];
 [btnBack addTarget:app action:@selector(popBack) forControlEvents:UIControlEventTouchUpInside];

 [view addSubview:btnBack];

 self.view = view;
 [view release];

}


- (void)viewDidLoad {
 [super viewDidLoad];
}


- (void)chooseSubject {
 FurballAppDelegate *app = [[UIApplication sharedApplication] delegate];
 SubjectViewController *subjectController = [[SubjectViewController alloc] init];
 [app pushNext:subjectController];
}


- (void)dealloc {
 [super dealloc];
}


@end

所有推送我的所有文件都有效。当我触摸它时,即使是“btnBack”,也会将导航控制器弹回到MainViewController ...但是当我创建一个与StartViewController上的按钮相同的后退按钮时,在SubjectViewController上它会给我一个奇怪的错误。

我非常感谢任何帮助:)

3 个答案:

答案 0 :(得分:3)

由于您意识到这意味着您正在尝试访问无效的内存地址,因此您需要检查代码是否存在无效的内存访问。

幸运的是,对于此错误,它通常位于您收到EXEC_BAD_ACCESS的行上。查看该行上的对象和指针。它们都有意义吗?如果没有,请备份一条线。洗涤,冲洗并重复。在某个地方,你没有正确地分配一个对象,过早发布它,堆栈损坏,或者某些变量指向随机垃圾。

在收到错误的地方发布一些代码可能会让我们发现错误。但是,如果不能在调试器中单步执行,也可能无法看到。

答案 1 :(得分:1)

弹出视图控制器时获取EXEC_BAD_ACCESS会让我怀疑在视图控制器中的dealloc方法中触发了错误。释放一个对象两次,或释放一个自动释放的对象?

答案 2 :(得分:0)

我没有具体找到我在哪里遇到内存问题,但我使用了另一种方法,创建了我自己的导航控制器类,扩展了UIViewController类,它对我正在使用的应用程序工作得更好。它使用非常少的内存,但按类名记忆控制器,因此添加所有UIViewControllers都不起作用。但这不是我想要的。我有很多视图控制器都有不同的类名,这很好用:)

FurballNavigationController.h

//
// FurballNavigationController.h
// Furball
//

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>


@class UIViewController;
@protocol FurballNavigationDelegate;


@interface FurballNavigationController : UIViewController <FurballNavigationDelegate> {
    NSMutableArray *viewControllers;
    int currentController;
    UIViewController *pendingView;
    int pendingDirection;
}


@property (nonatomic, retain) NSMutableArray *viewControllers;
@property (nonatomic) int currentController;


- (id)initWithRootViewController:(UIViewController *)viewController;
- (id)initWithViewControllers:(NSArray *)controllers;

- (void)addObject:(id)object;
- (void)removeObject:(unsigned int)index;

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)yesOrNo;
- (UIViewController *)popViewControllerAnimated:(BOOL)yesOrNo;
- (void)popToRootViewControllerAnimated:(BOOL)yesOrNo;

- (void)animateSlide:(UIViewController *)viewController direction:(NSString * const)direction;


@end


@protocol FurballNavigationDelegate


@optional


- (void)viewFinishedAnimation;

- (void)viewShouldPush:(UIViewController *)viewController;
- (void)viewWillPush:(UIViewController *)viewController;
- (void)viewDidPush:(UIViewController *)viewController;

- (UIViewController *)viewShouldPopAnimated:(BOOL)yesOrNo;
- (UIViewController *)viewWillPopAnimated:(BOOL)yesOrNo;
- (UIViewController *)viewDidPopAnimated:(BOOL)yesOrNo;


@end

FurballNavigationController.m


//
// FurballNavigationController.m
// Furball
//


#import "FurballNavigationController.h"

@implementation FurballNavigationController


@synthesize viewControllers;
@synthesize currentController;


- (id)init {

    NSMutableArray *arr = [[NSMutableArray alloc] init];
    self.viewControllers = arr;
    [arr release];

    currentController = 0;
    pendingView = nil;
    pendingDirection = 0;

    return self;

}


- (id)initWithRootViewController:(UIViewController *)viewController {

    if(self = [self init]) {
        if(viewController == nil) {
            viewController = [[UIViewController alloc] init];
            viewController.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
            [viewController.view setBackgroundColor:[UIColor redColor]];
        }
        [self addObject:viewController];
        self.view = viewController.view;
    }

    return self;

}


- (id)initWithViewControllers:(NSArray *)controllers {
    if(self = [self initWithViewControllers:[controllers objectAtIndex:0]])  {
        viewControllers = (NSMutableArray *)controllers;
    }
    return self;
}


- (void)addObject:(id)object {
    [viewControllers addObject:[NSString stringWithFormat:@"%@", [object class]]];
}


- (void)removeObject:(unsigned int)index {
    [viewControllers removeObjectAtIndex:(NSInteger)index];
}


- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)yesOrNo {

    pendingView = viewController;
    pendingDirection = 1;

    yesOrNo ? [self animateSlide:viewController direction:kCATransitionFromRight] : [self viewFinishedAnimation];

}

- (UIViewController *)popViewControllerAnimated:(BOOL)yesOrNo {

    UIViewController *controller = [[NSClassFromString([viewControllers objectAtIndex:currentController-1]) alloc] init];

    pendingView = controller;
    pendingDirection = -1;

    yesOrNo ? [self animateSlide:controller direction:kCATransitionFromLeft] : [self viewFinishedAnimation];

    return controller;

}


- (void)popToRootViewControllerAnimated:(BOOL)yesOrNo {

    UIViewController *controller = [[NSClassFromString([viewControllers objectAtIndex:0]) alloc] init];

    pendingView = controller;
    pendingDirection = -2;

    yesOrNo ? [self animateSlide:controller direction:kCATransitionFromLeft] : [self viewFinishedAnimation];

}


- (void)animateSlide:(UIViewController *)viewController direction:(NSString * const)direction {

    UIView *currentView = self.view;
    UIView *theWindow = [currentView superview];

    UIView *newView = viewController.view; 

    [currentView removeFromSuperview];
    [theWindow addSubview:newView];

    CATransition *animation = [CATransition animation];
    [animation setDuration:0.5];
    [animation setType:kCATransitionPush];
    [animation setSubtype:direction];
    [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

    [[theWindow layer] addAnimation:animation forKey:@"SwitchToView1"];

    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(viewFinishedAnimation) userInfo:nil repeats:NO]; timer;

}


- (void)viewFinishedAnimation {

    self.view = pendingView.view;
    if(pendingDirection > 0) {
        [self addObject:pendingView];
        currentController++;
    }
    else
    if(pendingDirection == -1) {
        [self removeObject:currentController];
        currentController--;
    }
    else
    if(pendingDirection == -2) {
        for(int i = 1; i < [viewControllers count]; i++)
            [self removeObject:i];
        currentController = 0;
    }

}


- (void)viewShouldPush:(UIViewController *)viewController {

}


- (void)viewWillPush:(UIViewController *)viewController {

}


- (void)viewDidPush:(UIViewController *)viewController {

}


- (UIViewController *)viewShouldPopAnimated:(BOOL)yesOrNo {
    return [[UIViewController alloc] init];
}


- (UIViewController *)viewWillPopAnimated:(BOOL)yesOrNo {
    return [[UIViewController alloc] init];
}


- (UIViewController *)viewDidPopAnimated:(BOOL)yesOrNo {
    return [[UIViewController alloc] init];
}


@end

感谢其他人的帮助:D