我收到以下错误。

EXC_BAD_ACCESS
KERN_INVALID_ADDRESS
[UITextField keyboardInputChangedSelection:]

直到最新的崩溃报告为止,我一直无法重现此崩溃。

我根据自己的应用程序中是否设置了密码 / 密码,从didFinishLaunchingWithOptionsapplicationWillEnterForeground调用此视图控制器。

现在这是奇怪的事情。

在以下情况下会发生崩溃。
  • 我在没有设置密码的情况下运行我的应用程序,我设置了密码。
  • 然后按主页按钮。
  • 该视图控制器弹出,我输入图钉,然后视图被关闭。
  • 然后我按下主页按钮。
  • 我进入应用程序,出现图钉屏幕。
  • 我按回家。
  • 然后进入应用程序,我崩溃了。

  • 我正在使用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)确保您的PasscodeViewControllerdealloc方法清除了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];
            }
        }
    }
    

    您的PasscodeViewControllerdealloc应该如下所示:
    - (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/

    10-09 02:53