EXC_BAD_ACCESS с iPhone SDK UINavigationController - PullRequest
0 голосов
/ 13 августа 2010

Хорошо, я пытаюсь использовать простой UINavigationController с iPhone SDK в XCode, и он хорошо работает при нажатии, но если пройти 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 ]

3 голосов
/ 13 августа 2010

Поскольку вы понимаете, что это означает, что вы пытаетесь получить доступ к неверному адресу памяти, вам нужно проверить свой код на наличие недопустимых обращений к памяти.

К счастью, из-за этой ошибки она обычно находится на той линии, где вы получаете EXEC_BAD_ACCESS. Посмотрите на объекты и указатели на этой линии. Все ли они имеют смысл? Если нет, сделайте резервную копию строки. Вымойте, промойте и повторите. Где-то вы не распределяете объект должным образом, освобождаете его слишком рано, имеете повреждение стека или некоторую переменную, указывающую на случайный мусор.

Размещение некоторого кода в месте, где вы получите сообщение об ошибке, может позволить нам определить ошибку. Однако также возможно, что это невозможно увидеть без возможности пошагового выполнения в отладчике.

1 голос
/ 13 августа 2010

Получение EXEC_BAD_ACCESS при подключении контроллера представления заставило бы меня заподозрить, что ошибка вызвана в методе dealloc в контроллере представления.Освобождение объекта дважды или автоматическое освобождение объекта?

0 голосов
/ 15 августа 2010

Я специально не выяснил, где у меня проблема с памятью, но я использовал альтернативный метод, создав собственный класс контроллера навигации, который расширил класс 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

...