如果我在从委托访问我的视图时得到 EXC_BAD_ACCESS,这是不是意味着我有内存泄漏?
Posted
技术标签:
【中文标题】如果我在从委托访问我的视图时得到 EXC_BAD_ACCESS,这是不是意味着我有内存泄漏?【英文标题】: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)。此外,在分析中有几个警告,但没有什么严重的(例如蓝色)。
【问题讨论】:
【参考方案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
【讨论】:
以上是关于如果我在从委托访问我的视图时得到 EXC_BAD_ACCESS,这是不是意味着我有内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章