zoukankan      html  css  js  c++  java
  • Fuck self.delegate = self

    故事背景如下,我有一个UITextField的子类MyTextField,创建了MyTextField的实例tf。我希望tf对应的键盘显示done按钮。代码如下:

     1 @interface MyTextField : UITextField
     2 @end
     3 
     4 MyTextField* tf = [[MyTextField alloc] initWithFrame:someframe];
     5 tf.returnKeyType = UIReturnKeyDone;
    
    

    然后我希望,当done被按下的时候,键盘关闭,通常的做法是给TextField一个delegate,监听textFieldShouldReturn,当done被按下时,会回调delegate的textFieldShouldReturn方法,代码如下:

     8 @interface TextFieldDelegate : NSObject<UITextFieldDelegate>
     9 @end
    10 
    11 @implementation TextFieldDelegate
    12 - (BOOL)textFieldShouldReturn:(UITextField *)textField
    13 {
    14     [textField resignFirstResponder];
    15     return YES;
    16 }
    17 @end
    18 
    19 tf.delegate = [[TextFieldDelegate alloc] init];

    这是比较常规的做法,但是要新建一个类,新建一个对象,用完了还要释放这个对象,成本很大。这时我产生了个偷懒的想法,我自己的事情我就自己做吧,我做我自己的代理,self.delegate = self。代码如下,

    23 @interface MyTextField : UITextField<UITextFieldDelegate>
    24 @end
    25 
    26 @implementation MyTextField
    27 - (BOOL)textFieldShouldReturn:(UITextField *)textField
    28 {
    29     [textField resignFirstResponder];
    30     return YES;
    31 }
    32 @end
    33 
    34 MyTextField* tf = [[MyTextField alloc] initWithFrame:someframe];
    35 tf.returnKeyType = UIReturnKeyDone;
    36 tf.delegate = tf;
    37 
    
    

    干净利落,然后恶梦就开始了。运行这段代码,点击输入框,先是程序就再不响应了,XCode也没什么有用的提示,试一两次,XCode也不再响应了。


    这个问题不是我自己解决的,我求助了google。在MyTextField的实现中加入以下函数,

    39 - (BOOL)respondsToSelector:(SEL)aSelector
    40 {
    41     return [super respondsToSelector:aSelector];
    42 }

    在这个函数中打个断点,再次执行,程序运行到断点后继续执行,会不断的运行到这个断点,然后不断继续,会发现,最终程序在这里无限递归了,参数始终是keyboardInputChangedSelection​,直到栈溢出,程序崩溃。


    现在我们知道原因了,为什么呢?猜想一下,这个函数的内部大概会是这样实现

    45 - (BOOL)respondsToSelector:(SEL)aSelector
    46 {
    47     switch(aSelector)
    48     {
    49         ...
    50         case keyboardInputChangedSelection:
    51             return [self.delegate respondsToSelector:aSelector];
    52         ...
    53     }
    54 }
    
    

    这个问题已经不在我们能看到的代码层面了,所以即便能解决,也只能非常暴力的重写respondsToSelector,这个和我们要偷懒的初衷不符。


    总结一下,self.delegate = self这种写法,在遇到

    56 -(void)method
    57 {
    58     [self.delegate method];
    59 }
    

    这种用法的时候,会发生无限递归导致崩溃,一定要避免。


  • 相关阅读:
    C#生成CHM文件(外篇使用hha.dll)
    prototype原理详解
    避免在代码中直接任意使用ConfigurationManager.AppSettings
    页面生命周期的来龙去脉(详细)
    nRF52832 SAADC sampling
    nRF52832开发日志--SAADC调试
    boost学习笔记(七)---date_time库
    Boost学习笔记(六) progress_display注意事项
    Boost学习笔记(五) progress_display
    扩展progress_timer的计时精度
  • 原文地址:https://www.cnblogs.com/linnguo/p/5058423.html
Copyright © 2011-2022 走看看