我收到以下错误。
EXC_BAD_ACCESS
KERN_INVALID_ADDRESS
[UITextField keyboardInputChangedSelection:]
直到最新的崩溃报告,我一直无法重现这次崩溃。
我从didFinishLaunchingWithOptions
和applicationWillEnterForeground
调用此视图控制器,具体取决于我的应用中是否设置了密码 / 图钉。
现在这是奇怪的事情。
崩溃发生在以下情况中。
我正在使用arc,我在iOS6上重现了崩溃。
下面是我的代码,我只是看不到问题?
.h文件
#import <UIKit/UIKit.h>
#define PVSectionFooterDefault @"Enter your PIN"
#define PVSectionFooterInvalid @"Invalid!"
#define PVSectionFooterCorrect @"Correct!"
@interface PasscodeViewController : UIViewController <UITableViewDelegate,
UITableViewDataSource, UITextFieldDelegate>{
IBOutlet UITableView *passcodeTable;
IBOutlet UILabel *lblMessage;
}
@property (nonatomic, strong) UITableView *passcodeTable;
@property (nonatomic, strong) UITextField *txtPassword;
@property (nonatomic, strong) UILabel *lblMessage;
@end
.m文件
#import "PasscodeViewController.h"
#import "AppDelegate.h"
@implementation PasscodeViewController
@synthesize passcodeTable;
@synthesize txtPassword;
@synthesize lblMessage;
- (void)viewDidLoad {
[super viewDidLoad];
//[passcodeTable setBackgroundColor:[UIColor clearColor]];
//[passcodeTable setBackgroundView:nil];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
lblMessage.shadowColor = [UIColor whiteColor];
lblMessage.shadowOffset = CGSizeMake(0.0, 1.0);
lblMessage.font = [UIFont systemFontOfSize:14];
lblMessage.textColor = [UIColor darkGrayColor];
lblMessage.text = PVSectionFooterDefault;
txtPassword.isAccessibilityElement = YES;
txtPassword.accessibilityLabel = @"Enter PIN";
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(willShowKeyboard:)
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didShowKeyboard:)
name:UIKeyboardDidShowNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardDidShowNotification object:nil];
}
- (void)willShowKeyboard:(NSNotification *)notification {
[UIView setAnimationsEnabled:NO];
}
- (void)didShowKeyboard:(NSNotification *)notification {
[UIView setAnimationsEnabled:YES];
}
#pragma mark - Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
CGRect frame = CGRectMake(cell.frame.origin.x+205,
cell.frame.origin.y+7, 90, 31);
txtPassword = [[UITextField alloc] initWithFrame:frame];
txtPassword.delegate = self;
txtPassword.borderStyle = UITextBorderStyleRoundedRect;
txtPassword.font = [UIFont systemFontOfSize:17.0];
txtPassword.backgroundColor = [UIColor whiteColor];
txtPassword.contentVerticalAlignment =
UIControlContentVerticalAlignmentCenter;
txtPassword.keyboardType = UIKeyboardTypeNumberPad;
txtPassword.returnKeyType = UIReturnKeyDone;
txtPassword.secureTextEntry = YES;
txtPassword.clearButtonMode = UITextFieldViewModeAlways;
cell.textLabel.text = @"Enter PIN";
[cell addSubview:txtPassword];
[txtPassword becomeFirstResponder];
}
return cell;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
return YES;
}
- (BOOL) textFieldShouldClear:(UITextField *)textField {
lblMessage.text = PVSectionFooterDefault;
return YES;
}
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
BOOL res = TRUE;
NSString *newString = [textField.text
stringByReplacingCharactersInRange:range
withString:string];
if ([newString length] == 4) {
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
NSString *strPassword = [myDefaults stringForKey:@"pass"];
if (strPassword == nil) {
strPassword = @"";
}
if (![newString isEqualToString:strPassword]) {
lblMessage.text = PVSectionFooterInvalid;
} else {
lblMessage.text = PVSectionFooterCorrect;
AppDelegate *appDel = (AppDelegate*)
[[UIApplication sharedApplication] delegate];
appDel.gbooShowingGetStartedPasswordAsk = FALSE;
[self.view removeFromSuperview];
}
} else if ([newString length] < 4) {
lblMessage.text = PVSectionFooterDefault;
}
res = !([newString length] > 4);
return res;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
@end
app delegate确实已启动
if (![strPassword isEqualToString:@""]) {
self.gbooShowingGetStartedPasswordAsk = TRUE;
lvc = [[PasscodeViewController alloc]
initWithNibName:@"PasscodeView" bundle:nil];
lvc.view.frame = CGRectMake(0, 20, 320, 460);
[window addSubview:lvc.view];
}
和....
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
if (self.gbooShowingGetStartedPasswordAsk == FALSE) {
NSString *strPassword = [myDefaults stringForKey:@"pass"];
if (strPassword == nil) {
strPassword = @"";
}
if (![strPassword isEqualToString:@""]) {
lvc = [[PasscodeViewController alloc]
initWithNibName:@"PasscodeView" bundle:nil];
int th = self.window.frame.size.height;
lvc.view.frame = CGRectMake(0, 20, 320, th);
lvc.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
[window addSubview:lvc.view];
}
}
}
答案 0 :(得分:3)
考虑lvc
何时不是nil
,并且具有超级视图,并调用applicationWillEnterForeground:
,并将分支带入那里的主要代码块。您将lvc
分配给PasscodeViewController
的新实例,这可能会导致lvc
的旧值被取消分配。但是,其view
属性具有超级视图,因此不会与其一起取消分配。这些活动对象可能还会生成解除分配的视图控制器仍在监听的通知或操作。我还注意到你并不总是取消订阅dealloc中的通知或nil
文本字段的委托。
我的建议是:1)确保在实例化另一个实例之前删除lvc
的视图,并确保PasscodeViewController
的{{1}}方法清理可能悬空dealloc
的参考文献。
您的NSNotificationCenter
方法变为:
applicationWillEnterForeground:
您的- (void)applicationWillEnterForeground:(UIApplication *)application {
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
if (self.gbooShowingGetStartedPasswordAsk == FALSE) {
NSString *strPassword = [myDefaults stringForKey:@"pass"];
if (strPassword == nil) {
strPassword = @"";
}
if (![strPassword isEqualToString:@""]) {
[lvc.view removeFromSuperview]; // This line prevents the view from persisting
lvc = [[PasscodeViewController alloc]
initWithNibName:@"PasscodeView" bundle:nil];
int th = self.window.frame.size.height;
lvc.view.frame = CGRectMake(0, 20, 320, th);
lvc.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
[window addSubview:lvc.view];
}
}
}
PasscodeViewController
应如下所示:
dealloc
通过这些更改,不应再对已解除分配的视图控制器进行悬空引用,也不应在视图层次结构中显示孤立视图。
答案 1 :(得分:0)
txtPassword = [[UITextField alloc] initWithFrame:frame];
并且
[self.view removeFromSuperview];
看起来对我很怀疑。我不是ARC粉丝,但是当你从父母那里删除你的视图时,似乎你可以合理地释放UITextField。它可以出现在
中- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
呼叫。
所以你应该在viewDidLoad上初始化并分配你的txtPassword,而不是单元格的初始化。
就像你说你要离开并从后台重新启动你的应用程序。如果您的单元格已被释放,您可以重新分配新的txtPassword,并将旧版本保留在最后一个单元格中。所以你可能有多个具有相同委托分配的txtPassword。如果您的视图不显示,则在返回UITextfield方法之前,txtPassword的引用将不再有效。
就像我说的那样,请务必只分配一次txtPassword。所以把它放在viewDidLoad中,并在viewDidUnLoad中释放它。
记住我只是在猜测。希望它会对你有所帮助。