簡體   English   中英

如果從委托訪問我的視圖時得到EXC_BAD_ACCESS,這是否意味着我發生了內存泄漏?

[英]If I get EXC_BAD_ACCESS when accessing my view from a delegate, does that mean I have a memory leak?

我有一個這樣初始化的對象:

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)。 同樣,在分析時有一些警告,但沒有嚴重的警告(例如藍色)。

您需要在ProfileDateTableDelegate.m initWithTableView:方法中調用self.scrollView = viewscrollView = [view retain]

基本上發生的是,您的scrollView在可以訪問它之前已在其他視圖中釋放,因為即使您在屬性上指定了nonatomic,retain ,“委托”類也不以任何方式保留它。 由於您是直接在init中設置ivar,而不是使用setter屬性,因此不會在其上調用keep。 當直接使用實例變量,你必須調用retain ,如果你想保留它自己。

避免此錯誤的一種方法是在ivar之前或之后使用下划線_ (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];
}

您可以在此處找到有關所有這些的更多信息。

啊,可怕的EXC_BAD_ACCESS 在不閱讀所有代碼的情況下,這里有個提示,可以幫助您立即入門。 運行分析器。 然后,使用儀器中的“泄漏”工具。

有關詳細信息,以及有關導致這些錯誤的原因的出色鏈接以及有關如何修復的逐步說明,請查看以下問題的答案:

在Xcode4中查找EXC_BAD_ACCESS的原因-

將EXC_BAD_ACCESS隨機放置在不可能發生的地方

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM