iOS,KERN_INVALID_ADDRESS [UITextField keyboardInputChangedSelection:]

时间:2013-02-26 09:30:29

标签: iphone ios objective-c ios6

我收到以下错误。

EXC_BAD_ACCESS  
KERN_INVALID_ADDRESS 
[UITextField keyboardInputChangedSelection:]

直到最新的崩溃报告,我一直无法重现这次崩溃。

我从didFinishLaunchingWithOptionsapplicationWillEnterForeground调用此视图控制器,具体取决于我的应用中是否设置了密码 / 图钉

现在这是奇怪的事情。

崩溃发生在以下情况中。

  1. 我没有设置针脚运行我的应用程序,我设置了针脚。
  2. 然后按主页按钮。
  3. 此视图控制器会弹出,我输入图钉并取消视图。
  4. 然后按主页按钮。
  5. 我进入应用程序,出现图钉屏幕。
  6. 我回家了。
  7. 然后进入应用程序,我就崩溃了。
  8. 我正在使用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];
            }
        }
    }
    

    enter image description here

2 个答案:

答案 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中释放它。

记住我只是在猜测。希望它会对你有所帮助。