美文网首页
高效编写代码的方法(十九):Delegate要点

高效编写代码的方法(十九):Delegate要点

作者: 蜂猴 | 来源:发表于2016-06-30 09:59 被阅读240次

    在OC中有很多方式可以进行对象间的“通信”,其中一种方式就是通过设置代理。
    OC中使用代理的方式就不做过多介绍了。
    重点介绍下使用代理需要注意或者可以提高的地方。

    引用循环

    可以参照官方的代理写法:

    @property (nonatomic, weak, nullable) id <UITableViewDataSource> dataSource;
    @property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
    

    注意属性的修饰符是weak而不是strong,表示代理与委托之间的关系:
    代理或者别的对象可能持有委托,而委托不持有代理。
    声明为weak以防止引用循环。

    内省判断

    在真正执行代理方法之前,先判断delegate能否执行协议中声明的方法,一般如下判断:

    if ([_delegate respondToSelector:@selector(someMethod:)]){
            [_delegate someMethod:data];
    }
    

    这样判断的好处就是在于即时delegate没有实现方法,当delegate被触发想要执行时,也不会因为找不到方法而造成程序崩溃。

    命名与参数

    协议的方法命名除了要准确传达方法的意思(OC的传统)之外最好还能将所代理的对象作为参数写入命名中,比如一个数据加载器的协议方法:

    - (void)networkFetcher:(NetworkFetcher *)fetcher
            didReceiveData:(NSData *)data;
    

    这样的好处在于delegate在执行的时候可以判断出不同的委托对象从而执行不同的方法:

    - (void)networkFetcher:(NetworkFetcher *)fetcher
            didReceiveData:(NSData *)data{
          if(fetcher == _fetcherA){
            //do A
          }else{
            //do B
    }
    

    定向

    举个例子,应该就非常好理解了。

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    

    以上是一个WebView的原生代理,可以用来决定是否能发起某些特定的请求。

    我们自己也可以多使用类似的代理方法进行某些定向问题的判断。

    提供数据源

    有时候,我们不止希望delegate能处理一些回调的逻辑,还希望delegate能给我们的委托对象提供一些数据源。此时我们就可以使用名为“dataSource”(自己命名也可以)的代理来处理数据部分的问题。最经常使用的就是在tableview中,我们使用dataSource来提供cell的数量以及cell。

    使用delegate与dataSource分开的方式可以将逻辑与数据分开进行处理,显得比较清晰。

    快速内省

    一旦我们协议中有很多的代理方法时候,为了安全,我们每次执行都去进行一次respondToSelector的内省判断,那么整个过程就需要不断地重复写判断,显得非常麻烦。

    有一种简单的方法就是定义一个结构体,然后用该结构体来保存所有的内省判断的结果。
    举个例子:

    @interface NetworkFetcher(){
    struct {
        unsigned int didReceiveData :1;
        unsigned int didFailWithError:1;
        unsigned int didUpdateProgress:1;
        }_delegateFlag;
        }
    }
    

    以上结构体_delegateFlag就以三个1字节的数据用来保存是否响应代理方法的Bool值。
    在setDelegate:方法中我们进行统一判断和保存 ,如下:

    - (void)setDelegate:(id<NetworkFetcher>)delegate{
        _delegate = delegate;
        _delegateFlag.didReceiveData = [_delegate respondToSelector:@selector(networFetcher:didReceiveData:)];
        //省略
    }
    

    这样一来,在后续的判断中,我们可以直接使用_delegateFlag来判断代理能否响应方法。

    相关文章

      网友评论

          本文标题:高效编写代码的方法(十九):Delegate要点

          本文链接:https://www.haomeiwen.com/subject/cdyxjttx.html