UITextField 子类在 becomeFirstResponder 抛出奇怪的异常

Posted

技术标签:

【中文标题】UITextField 子类在 becomeFirstResponder 抛出奇怪的异常【英文标题】:UITextField subclass throwing weird exception at becomeFirstResponder 【发布时间】:2012-09-04 11:11:14 【问题描述】:

我有由 UINavigatableTextField 组成的字符框。每次输入后,响应者字符应该继承它的继任者。奇怪的是,在输入第一个字符期间,如果用户每次输入字符 'Q' 都会出现不同的异常,例如;

EXC_BAD_ACCESS,或 2012-09-04 14:42:42.600 Kelime Oyunu[6350:707]-[WebScriptObjectPrivate isForShortcutConversion]:无法识别的选择器发送到实例 0x21b870 2012-09-04 14:42:42.606 Kelime Oyunu[6350:707] * 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:'-[WebScriptObjectPrivate isForShortcutConversion]:无法识别的选择器发送到实例 0x21b870 '

被抛出。我的代码在下面收到异常,[next becomeFirstResponder] 行

- (void) moveToNextCharacter: (MBNavigatableTextField *) character

    dispatch_async(dispatch_get_current_queue(),
               ^
                   UIControl *next = [character nextField];

                   if(next == nil)
                   
                       [character endEditing:YES];
                   
                   else if ([next isKindOfClass:[UIButton class]])
                   
                       [next sendActionsForControlEvents: UIControlEventTouchUpInside];
                   
                   else
                   
                       [next becomeFirstResponder];
                   
                );

我该如何解决这个问题?提前致谢。

编辑 1:找到一个僵尸 [next resignFirstResponder](感谢 @PhillipMills)

编辑2:原来我的问题是由

引起的
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

    // Something done here...

    // code block of evil zombie summoner
    [textField setText:@"Some text"];

    // Something else done here

Profile->Instruments->Zombies 声明在 setText 期间:某个对象被释放(我猜这是之前的字符串)。

我仍然无法解决问题。我的目标是用新的用户输入(replacementString:) 更新上面的 textField。

【问题讨论】:

我认为您需要找出问题所在。单步执行代码(或使用日志消息)找到失败的行,然后引用实际的错误消息。 @DavidH 在评论之前看看我的其他问题。如果你找到答案,我一定会接受的。 isForShortcutConversion 是您的一个类中的方法吗? (如果是,请尝试在启用僵尸的情况下运行。) 快速的 Google 搜索表明它是与文本输入相关的私有方法,因此僵尸实验可能会有所帮助,因为您正在使用文本字段并且与 WebScriptObjectPrivate 没有明显的联系。 为什么是 dispatch_get_current_queue ?我宁愿将dispatch_get_main_queue 用于响应者操作,因为这与 UI 状态有关。 【参考方案1】:

所有到 UIKit 对象的消息都必须在主队列上完成。虽然情况可能如此,但此声明:

dispatch_async(dispatch_get_current_queue()

很麻烦,因为我们不知道您在哪个队列上收到消息。将其更改为:

dispatch_async(dispatch_get_main_queue()

所以它绝对清楚。

另外,在这一行下:

UIControl *next = [character nextField];

添加这些语句:

NSLog(@"Character CLASS %@", NSStringFromClass[character class]);
NSLog(@"next CLASS %@", NSStringFromClass[next class]);

确保这些是您认为应该是的。

编辑:关于“unsafe_unretained”的使用:如果 IBOutlet 包含在“self.view”中——这是主要视图——那么你应该在 ios 上使用弱——所以当视图消失。

关于“shouldChangeCharactersInRange”,如果您只是查看字符,则返回 YES。如果您更改文本本身 - 通过直接写入字段/视图,则返回 NO。如果您修改文本然后返回 YES,那么您实质上是在更改控件背后的数据,谁知道会产生什么后果。

【讨论】:

谢谢。正如@A-Live 所建议的那样,将 dispatch_async 队列固定为 dispatch_get_main_queue()。这是我的日志(如果记录不同的结果,尝试了几次): 2012-09-04 16:43:46.179 Kelime Oyunu[4675:f803] Character CLASS MBNavigatableTextField 2012-09-04 16:43:46.180 Kelime Oyunu[4675:f803 ] next CLASS MBNavigatableTextField 所以这些消息是你所期望的——类——它是正确的。然后当'[next becomeFirstResponder];'发送您会崩溃。您需要在所有异常上启用断点和中断,并查看其崩溃的位置。可能是最后一个收到“resign”消息的对象导致了崩溃。 僵尸向我展示了一些位于我的问题“编辑 2”部分下方的信息。还从 textField:shouldChangeCharactersInRange:replacementString: 中删除 [textField setText:@"Some text"] 以解决问题。我的目标仍然是用新的输入替换每个输入。 这不是解决方案,它只是避免问题。因此,如果您进行了该调用,那么“textField 在那时已被释放,或者您在设置文本时没有返回 NO(这可能会使 textField 混淆,可能不会但可能会)。您所有的 MBNavigatableTextFields 都被保留在强引用中?他们也拥有所有对象? 是的,你是对的,这只是在避免问题。仍然是最接近解决方案的事情,你在第一次评论接受解决方案时让我很害怕:)。

以上是关于UITextField 子类在 becomeFirstResponder 抛出奇怪的异常的主要内容,如果未能解决你的问题,请参考以下文章

子类化 UITextField

如何在 UITextField 子类中拦截来自键盘的文本输入事件

UITextField 子类 - 订阅事件

UITapGestureRecognizer 不适用于 UITextField 的自定义子类

UITextfield 子类没有响应 insertText:UIKeyInput 协议的方法

iOS:响应者辞职时,文本从子类 UITextfield 中消失