我有一个包含UITextView
的UIView
子类(MyView
)。我希望MyView
对所有UIResponder
方法使用UITextView
,比如
@implementation MyView
- (BOOL)canBecomeFirstResponder {
return _textView.canBecomeFirstResponder
}
- (BOOL)becomeFirstResponder {
return [_textView becomeFirstResponder];
}
- (BOOL)canResignFirstResponder {
return [_textView canResignFirstResponder];
}
- (BOOL)resignFirstResponder {
// UIResponder documentation says [super resignFirstResponder]
// must be called somewhere in this method
BOOL superResignedFirstResponder = [super resignFirstResponder];
if (superResignedFirstResponder) {
return [_textView resignFirstResponder];
} else {
return NO;
}
}
- (BOOL)isFirstResponder {
return [_textView isFirstResponder];
}
@end
然而,当我阅读苹果的Event Delivery:The Responder Chain文档时,我认为这可能是一个不正确的实现。我找不到任何关于如何用另一个UIResponder
创建UIResponder
的文档或帖子。
UIKit
的概念正好是1个firstResponder
,所以当MyView
处理-becomeFirstResponder
并返回YES
时,UIKit
认为MyView
就是firstResponder
似乎是合理的。然而,由于我依次调用-[MyView becomeFirstResponder]
中的-[UITextView becomeFirstResponder]
,所以两个必须中的一个获胜,一个必须失败。哪个赢,哪个输?如果UITextView
是firstResponder
,那么为什么-[MyView isFirstResponder]
要返回YES
?
有人有什么建议吗?我的上述实施是否正确?
尽管我发现了其他证据表明人们以同样的方式解决了这个问题。这个实现给我带来了问题。TLDR:我认为您不应该编写UIResponder
对象。
我的错误:
- 使用者调用
MyView
上的方法,而MyView
以编程方式调用-[UITextView becomeFirstResponder]
。从来没有人点击过MyView
的内部UITextView
- 消费者想要丢弃键盘。我们可以验证
UITextView
是firstResponder
,因为私有API-[UIApplication.sharedApplication.keyWindow firstResponder]
返回UITextView
- 使用者调用
[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]
,但此调用返回NO
。当进行此调用时,UIKit
不调用-[UITextView canPerformAction:withSender:]
或-[UITextView targetForAction:withSender:]
但是,如果改为:
- 用户点击
MyView
的UITextView
- 消费者想要丢弃键盘。我们可以验证
UITextView
是firstResponder
,因为私有API-[UIApplication.sharedApplication.keyWindow firstResponder]
返回UITextView
- 一个使用者调用
[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]
,现在这个调用返回YES
。在进行此调用时,UIKit
按预期调用-[UITextView canPerformAction:withSender:]
和-[UITextView targetForAction:withSender:]
,然后当然调用-[UITextView resignFirstResponder]
,这成功了
我不知道为什么在第一种情况下[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]
没有正确地委托给UITextView
,但我不得不假设,由于-[MyView becomeFirstResponder]
没有像文档所说的那样委托给[super becomeFirstResponder]
,所以出现了问题。我认为您不应该编写UIResponder
对象。
--编辑--
我仍然不确定出了什么问题,但我发现我的应用程序中有多个UIWindow
,我收到了知情人士的来信™多窗口应用程序可能偶尔会出现CCD_ 56问题。