我收到以下错误。
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
应用程序委托确实启动了
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];
}
}
}
最佳答案
考虑何时lvc
不是nil
,并且具有 super 视图,并且applicationWillEnterForeground:
被调用,并将分支带到那里的主要代码块中。您将lvc
分配给PasscodeViewController
的新实例,这很可能导致lvc
的旧值被释放。但是,其view
属性具有一个 super 视图,因此不会与其一起释放。这些 Activity 对象可能仍会产生释放的视图控制器仍在监听的通知或动作。我还注意到,您并非总是取消订阅文本字段的委托的dealloc或nil
中的通知。
那么,我的建议是:1)确保在实例化另一个实例之前删除lvc
的视图,以及2)确保您的PasscodeViewController
的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
应该如下所示:- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (txtPassword.delegate == self) {
txtPassword.delegate = nil; //docs indicate this is still an `assign` property so is not auto-zeroing in ARC and iOS 5+
}
}
进行了这些更改之后,就不应再有对已释放视图控制器的悬空引用,并且视图层次结构中也没有孤立的视图。
关于iphone - iOS,KERN_INVALID_ADDRESS [UITextField keyboardInputChangedSelection:],我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15085512/