【问题标题】:If I get EXC_BAD_ACCESS when accessing my view from a delegate, does that mean I have a memory leak?如果我在从委托访问我的视图时得到 EXC_BAD_ACCESS,这是否意味着我有内存泄漏?
【发布时间】:2011-11-11 16:55:54
【问题描述】:

我有一个对象,我 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)。此外,在分析中有几个警告,但没有什么严重的(例如蓝色)。

【问题讨论】:

    标签: objective-c ios


    【解决方案1】:

    您需要在ProfileDateTableDelegate.m 的initWithTableView: 方法中调用self.scrollView = view 或scrollView = [view retain]。

    基本上发生的情况是,您的 scrollView 在您能够访问它之前已在其他视图中被释放,因为您的“委托”类不会以任何方式保留它,即使您在您的财产上指定了 nonatomic,retain .由于您直接在 init 中设置 ivar 而不是使用 setter 属性,因此不会在其上调用保留。直接使用 ivar 时,如果要保留它,必须自己调用retain。

    避免此错误的一种方法是在您的 ivars 之前或之后使用下划线 _(Apple 使用 before,所以我使用 after 以避免私人 ivar 冲突),如下所示:

    在.h中:

    @interface{
        UIScrollView *scrollView_;
    }
    
    @property (nonatomic,retain) UIScrollView *scrollView;
    

    在 *.m 中:

    @synthesize scrollView = scrollView_;
    

    那么,你在init,你可以像这样保留进来的视图:

    scrollView_ = [view retain];
    

    只要确保你在dealloc中正确发布它:

    - (void)dealloc{
        [scrollView_ release], scrollView_ = nil;
        [super dealloc];
    }
    

    你可以找到更多关于这一切here的信息。

    【讨论】:

      【解决方案2】:

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

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

      finding reason for EXC_BAD_ACCESS - in Xcode4

      Random EXC_BAD_ACCESS in a place that it cannot happen

      【讨论】:

        猜你喜欢
        • 2014-12-07
        • 2013-03-09
        • 1970-01-01
        • 1970-01-01
        • 2012-02-20
        • 1970-01-01
        • 2016-07-14
        • 2010-12-29
        • 1970-01-01
        相关资源
        最近更新 更多