如果从代理访问我的视图时获得EXC_BAD_ACCESS,这是否意味着我有内存泄漏?

时间:2011-11-11 16:55:55

标签: objective-c ios

我有一个像 init 这样的对象:

pdtd = [[ProfileDataTableDelegate alloc] initWithTableView:profileDataTableView scrollView:contentScrollView];

所以我的view被传递给pdtd对象。我可以在此时记录我的视图,没有任何问题。当我在文本字段中单击并且滚动视图被告知要重新定位时,我得到错误。在我的表委托(pdtd)上我得到的错误给了我" EXC_BAD_ACCESS"在这个函数的第一行:

- (void)keyboardDidShow:(NSNotification *)notif {
    [self.scrollView setContentOffset:CGPointMake(0, 100) animated:YES]; // <-- ERROR SHOWS UP HERE

    [self.scrollView setContentSize:CGSizeMake([self.scrollView frame].size.width, 
                                               [self.scrollView frame].size.height + 100)];
}

这很奇怪,因为我在另一个视图上执行此操作并且工作正常。我不确定错误或如何从调试器获取更多信息。以下是相关类的相关函数。

ProfileViewController.h

...

#import "ProfileDataTableDelegate.h"


@interface ProfileViewController : UIViewController <UINavigationControllerDelegate> {
    UITableView *profileDataTableView;
    ProfileDataTableDelegate *pdtd;
    UINavigationBar *navBar;
    UIScrollView *contentScrollView;
}

...

@property (nonatomic, retain) IBOutlet UITableView *profileDataTableView;
@property (nonatomic, retain) ProfileDataTableDelegate *pdtd;
@property (nonatomic, retain) IBOutlet UINavigationBar *navBar;
@property (nonatomic, retain) IBOutlet UIScrollView *contentScrollView;

@end

ProfileViewController.m

...

- (void)viewDidLoad {
    [super viewDidLoad];

    //nav title
    [navBar.topItem setTitle:@"Your Profile"];

    [self.navigationController setNavigationBarHidden:NO];

    // nav bar button
    UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(saveBtnTouched:)];
    saveButton.enabled = false;
    [navBar.topItem setRightBarButtonItem:saveButton];

    pdtd = [[ProfileDataTableDelegate alloc] initWithTableView:profileDataTableView scrollView:contentScrollView];

    void (^block)(BOOL) = ^(BOOL is_valid) {
        if(is_valid == YES) {
            [saveButton setEnabled:YES];
        } else if(is_valid == NO) {
            [saveButton setEnabled:NO];
        }
    };

    [pdtd setValidatorBlock:block];
}

...

ProfileDateTableDelegate.h

...

#import "ValidatedTextViewTableCell.h"

typedef void (^ ValidatorBlock)(BOOL);

@interface ProfileDataTableDelegate : NSObject <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate> {
    UITableView *profileDataTableView;
    UIScrollView *scrollView;

        ...
}

- (id)initWithTableView:(UITableView *)tableView scrollView:(UIScrollView *)scrollView;

...

@property (nonatomic, retain) IBOutlet UITableView *profileDataTableView;
@property (nonatomic, retain) UIScrollView *scrollView;

@end

ProfileDateTableDelegate.m

...

@implementation ProfileDataTableDelegate

@synthesize profileDataTableView;
@synthesize profileDataTableLabels;
@synthesize scrollView;

@synthesize emailCell, phoneCell, nameCell;
@synthesize validatedTextViewTableCell;
@synthesize validatorBlock;


- (id)initWithTableView:(UITableView *)tableView scrollView:(UIScrollView *)view {
    self = [super init];

    if(self) {
        profileDataTableView = tableView;
        [profileDataTableView setDelegate:self];
        [profileDataTableView setDataSource:self];

        scrollView = view;

        profileDataTableLabels = [[NSArray alloc] initWithObjects:@"Name", @"Email", @"Phone", nil];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector (keyboardDidShow:)
                                                     name: UIKeyboardDidShowNotification object:nil];

        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector (keyboardDidHide:)
                                                     name: UIKeyboardDidHideNotification object:nil];
    }

    return self;
}

...

- (void)keyboardDidShow:(NSNotification *)notif {
    //NSLog(@"keyboard did show %@", notif); // notif gives coordinates etc
    //[scrollView setContentOffset:CGPointMake(0, 480 - 372) animated:YES];

    [self.scrollView setContentOffset:CGPointMake(0, 100) animated:YES];

    [self.scrollView setContentSize:CGSizeMake([self.scrollView frame].size.width, 
                                               [self.scrollView frame].size.height + 100)];

    //[scrollView setFrame:CGRectMake(0, 0, 320, 320)];


    // disable scrolling because it resets the rect position
    //[scrollView setScrollEnabled:NO];
}

...

@end

我不确定如何获取堆栈跟踪信息(Xcode 4.2)。此外,在分析时有几个警告,但没有什么严重的(例如蓝色)。

2 个答案:

答案 0 :(得分:4)

您需要在self.scrollView = view的{​​{1}}方法中致电scrollView = [view retain]initWithTableView:

基本上发生的事情是,在您能够访问之前,您的scrollView正在其他视图中发布,因为您的“委托”类不会以任何方式保留它,即使您已指定ProfileDateTableDelegate.m你的财产。由于您直接在nonatomic,retain中设置ivar而不是使用setter属性,因此不会在其上调用retain。直接使用ivar时,如果要保留,请自行致电init

避免此错误的一种方法是在你的ivars之前或之后使用下划线retain(Apple之前使用,所以我用它来避免私人的ivar碰撞),如下所示:

在.h:

_

in * .m:

@interface{
    UIScrollView *scrollView_;
}

@property (nonatomic,retain) UIScrollView *scrollView;

然后,你在@synthesize scrollView = scrollView_; ,你可以像这样保留视图:

init

请确保在scrollView_ = [view retain]; 中正确发布:

dealloc

您可以找到有关所有这些here的更多信息。

答案 1 :(得分:1)

啊,可怕的EXC_BAD_ACCESS。没有完成所有代码,这里有一个提示,可以让你立即开始。运行分析器。然后,使用Instruments中的Leaks工具。

有关详细信息,以及导致这些错误的原因的详尽链接以及如何修复的分步说明,请查看这些问题的答案:

finding reason for EXC_BAD_ACCESS - in Xcode4

Random EXC_BAD_ACCESS in a place that it cannot happen