I have an object that I init like so:
pdtd = [[ProfileDataTableDelegate alloc] initWithTableView:profileDataTableView scrollView:contentScrollView];
so my view is passed to the pdtd object. I can log my view out at this point with no problem. I get the error when I click inside a text field and the scroll view is told to reposition. It’s on my table delegate (pdtd) that I get the error which gives me “EXC_BAD_ACCESS” in the first line of this function:
- (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)];
}
Which is weird because I’m doing this on another view and it works fine. I’m not sure what’s wrong or how to get more info from the debugger. Below are related functions from the associated classes.
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
I’m not sure how to get stack trace info (Xcode 4.2). Also, on analyze there are a couple of warnings, but nothing serious (eg. blue).
You need to call
self.scrollView = viewORscrollView = [view retain]in yourinitWithTableView:method inProfileDateTableDelegate.m.Basically what is happening is that your scrollView is being released in some other view before you are able to access it since your “delegate” class does not retain it in any way, even though you have specified
nonatomic,retainon your property. Since you are setting the ivar directly ininitinstead of using the setter property, the retain is not being called on it. When using the ivar directly, you must callretainyourself if you want it retained.One way to avoid this error is to use an underscore
_before or after your ivars (Apple uses before, so I use after to avoid private ivar collisions), like so:in .h:
in *.m:
Then, you in
init, you can retain the view coming in like so:Just make sure you properly release it in
dealloc:You can find more info about all this here.