返回键在 UIAlertView 上的 UITextField 中不起作用 .. SIGSEGV

Posted

技术标签:

【中文标题】返回键在 UIAlertView 上的 UITextField 中不起作用 .. SIGSEGV【英文标题】:Return key doesn't work in a UITextField on a UIAlertView .. SIGSEGV 【发布时间】:2011-12-01 15:00:33 【问题描述】:

当我在UIViewController 中使用UITextField 时,我能够使用ShouldReturn 捕获返回键的键盘事件:

public override void ViewDidLoad ()
       
    this.txtPassword.ShouldReturn = (tf) => 
                   
        tf.ResignFirstResponder();              
        return true;
    ;

...但是当我使用UIAlertView 时,我在尝试使用ShouldReturn 时遇到了SIGSEGV 错误:

public override void ViewDidLoad ()


    base.ViewDidLoad ();            
    loginScreen = new UIAlertView();
    loginScreen.Title = "Login";            
    loginScreen.AlertViewStyle = UIAlertViewStyle.LoginAndPasswordInput;//type login and pass
    loginScreen.AddButton ("Cancel");
    //username
    UITextField usernameField = loginScreen.GetTextField(0);
    usernameField.KeyboardType = UIKeyboardType.Default;
    usernameField.ReturnKeyType = UIReturnKeyType.Next;
    usernameField.ClearButtonMode = UITextFieldViewMode.WhileEditing;
    //password
    UITextField passwordField = loginScreen.GetTextField(1);
    passwordField.KeyboardType = UIKeyboardType.Default;
    passwordField.ReturnKeyType = UIReturnKeyType.Next;
    passwordField.ClearButtonMode = UITextFieldViewMode.WhileEditing;

    //(Error SIGSEV happens here!!! and the resignfirstresponder doesn't work)
    passwordField.ShouldReturn = (tf) => 
                   
        tf.ResignFirstResponder();
        return true;
     ;
    loginScreen.Show();

我不知道到底发生了什么,这可能是一个错误或者我做错了什么?

【问题讨论】:

这可能发生在 GC 收集(托管)实例(例如 passwordField)时。现在您提供的代码看起来是正确的 - 但也许某些东西(稍后)允许处置 loginScreen(这也将允许处置文本字段)。你能提供一个完整的测试用例吗?您可以将此类附加到bugzilla.xamarin.com 上的错误报告中,谢谢! 我在 MT 5.2.11 上使用完全相同的代码,但有一点不同:我的 ShouldReturn 看起来像这样:pwd.ShouldReturn = delegate passwordField.ResignFirstResponder();返回真; - 所以我正在捕获我想辞职的文本字段,这似乎阻止了收集。 【参考方案1】:

在 ViewDidLoad 范围内创建并且在方法执行后应该保持活动状态(不是垃圾回收)的对象,必须在包含类中具有引用。

private UIAlertView _loginScreen; // Declare reference.
private UITextField _usernameField; // Declare reference.
private UITextField _passwordField; // Declare reference.

public override void ViewDidLoad ()

    base.ViewDidLoad ();            
    _loginScreen = new UIAlertView(); // Set reference.
    _loginScreen.Title = "Login";            
    _loginScreen.AlertViewStyle = UIAlertViewStyle.LoginAndPasswordInput;
    _loginScreen.AddButton ("Cancel");
    //username
    _usernameField = _loginScreen.GetTextField(0); // Set reference.
    _usernameField.KeyboardType = UIKeyboardType.Default;
    _usernameField.ReturnKeyType = UIReturnKeyType.Next;
    _usernameField.ClearButtonMode = UITextFieldViewMode.WhileEditing;
    //password
    _passwordField = _loginScreen.GetTextField(1); // Set reference.
    _passwordField.KeyboardType = UIKeyboardType.Default;
    _passwordField.ReturnKeyType = UIReturnKeyType.Next;
    _passwordField.ClearButtonMode = UITextFieldViewMode.WhileEditing;

    //(Error SIGSEV happens here!!! and the resignfirstresponder doesn't work)
    _passwordField.ShouldReturn = (tf) => // Use reference.
    
        // This delegate will be executed at a later time, ensure its owner
        // object is rooted with a reference.
        tf.ResignFirstResponder();
        return true;
     ;
    _loginScreen.Show();

用户poupou当然是第一个回答这个问题的,但我想把它和示例代码一起放在一起,因为这个错误让我咬了太多次。很难调试,并且可能在垃圾回收后意外发生。

我的经验法则;每当使用new 或工厂方法时,都应该存储一个引用,除非该对象超出范围,或者已经通过引用嵌套到另一个对象中。

出于这个原因,我在字段前加上下划线,它表示“这个对象将跨越这个对象的方法范围,并且可以很容易地与方法变量(没有下划线的变量)区分开来。

现在,对于这种情况,GetTextField() 似乎创建了一个包装对象而不是引用。虽然loginScreen 字段是有根的,但从GetTextField() 返回的对象不是根,并且容易被垃圾回收。由于意外行为,我会说这是 MonoTouch API 中的错误。

【讨论】:

用户要求 UITextView 而不是 UITextField @MyKuLLSKI 发生 SIGSEGV 错误是因为在 ShouldReturn lambda 中引用的垃圾收集 UITextField(请参阅 tf 参数)。这就是问题。与 UIAlertView 无关。在投反对票之前阅读。

以上是关于返回键在 UIAlertView 上的 UITextField 中不起作用 .. SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章

uialertview 上的活动指示器

自定义 UIAlertView,委托上的消息更改

如何使 UIAlertView 上的按钮多行显示?

用户按下了 UIAlertView 上的哪个按钮?

iOS7上的UIAlertView崩溃私有方法

键盘上的PERIOD键在啥地方?