发送到释放实例的 UITextField textInputView 消息

UITextField textInputView message sent to deallocated instance

我在点击 UITextField 时发生崩溃。我有两个控制器,比方说 AB。当我在控制器 A 中模态显示控制器 B 并点击 UITextField 时,一切正常。然后我关闭控制器 B,并再次呈现它。这次当我单击 UITextField 时发生崩溃。当我在我的方案中启用 NSZombie 时,出现崩溃消息 - -[UITextField textInputView]: message sent to deallocated instance.

我没有在 UITextField 上设置 UITextFieldDelegate。当我尝试使用 Instruments -> Zombies 进行调试时,双击某些 release/retain 历史记录行时没有源代码(不可用)。

我的方案的构建配置调试。 Xcode 版本为 7.2.1。崩溃仅在 iOS 8 上发生。 iOS 9 没问题。

PS:当我尝试重新符号化应用程序时,我发现缺少一个 System Frameworks dyld。然后我按 Locate 按钮并打开我的调试应用程序的 dsym 文件,但出现错误消息 "The specified path didn't locate a dSYM for any of the selected libraries."

更新 1:

A控制器:

#import <UIKit/UIKit.h>

@interface A : UIViewController
@end

#import "A.h"
#import "RoundedButton.h"

@interface A ()
@property (weak, nonatomic) IBOutlet RoundedButton *signInButton;
@end

@implementation A

- (void)viewDidLoad {
    [super viewDidLoad];

    [self configUI];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleDefault;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Segue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"signIn"]) {

    }
}

#pragma mark - Config UI

- (void)configUI {
    // setup ui    
}

- (void)dealloc {
    NSLog(@"%@ deallocated", NSStringFromClass([self class]));
}

@end

B 控制器:

#import <UIKit/UIKit.h>

@interface B : UIViewController
@end

#import "B.h"
#import "SKFormTextField.h"
#import "RoundedButton.h"

@interface B () 
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet RoundedButton *signInButton;
@end

@implementation B {
    SKAlertView *alertView;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self configUI];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
}

#pragma mark - Actions

- (IBAction)cancelSignIn:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - Config UI

- (void)configUI {
    self.navigationController.navigationBarHidden = YES;

    self.textField.secureTextEntry = true;
    self.textField.autocorrectionType = UITextAutocorrectionTypeNo;
}

- (void)dealloc {
    NSLog(@"%@ deallocated", NSStringFromClass([self class]));
}

@end

更新 2:

当我调用 UITextField 时,与 self.textField.text = @"Hello, World!"; 一样,没有崩溃。只有当我 pan/touch UITextField 或调用 [self.textField becomeFirstResponder]; 时它才会崩溃。

终于,我找到了崩溃的原因。我有 UITextField 名为 UITextField (AutoSuggestion) 的扩展,我在其中调用了 dealloc 方法来删​​除自己的观察者。

代码示例:

/* .h file */
#import <UIKit/UIKit.h>
// some protocol
@interface UITextField (AutoSuggestion)
// some properties and methods
@end

/* .m file */
#import "UITextField+AutoSuggestion.h"
#import <objc/runtime.h>
@implementation UITextField (AutoSuggestion)
- (void)observeTextFieldChanges {
    self.layer.masksToBounds = NO;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(toggleAutoSuggestion:) name:UITextFieldTextDidChangeNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideAutoSuggestion) name:UITextFieldTextDidEndEditingNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(getKeyboardHeight:)
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidChangeNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
}
// other methods
@end

在我删除 dealloc 方法后崩溃消失了。因此我决定寻找新的方法来实现自我暗示功能。

有趣的是,我没有在代码中任何地方导入头文件,而是发生了崩溃。