关于 iOS 中数据交付

作者: YxxxHao | 来源:发表于2017-02-07 14:10 被阅读360次

    在 iOS 的数据交付(数据传递)方式中,常用的方式有:参数传递、Delegate、Notification、Block、KVO 和 Target-Action。下面逐一说明下这几种方式:

    参数传递

    这是最常用的一种方法了,就是在一个类中声明一个 public 的属性,提供给调用者,举个例子:

    /* A.h */
    @interface A : UIView;
    
    @property (nonatomic, strong) UIButton *title;
    
    @end
    
    /* B.m */
    A *a = [A alloc] init];
    a.title = @"title";
    

    这个就是最简单的参数传递的例子了,也是最常用的一种方式。

    Delegate

    在 iOS 中说到 delegate 自然就是想到 protocol,想想当初为了面试,还真不少背概念,其实也很好理解,举个比较形象的例子:

    某神壕,想在深圳出售一套200方的房子(想想我干一辈子也买不起~~~),但神壕不想自己搞,然后交给了中介(delegate)去卖,但是神壕还是有一定要求的,比如最少多少钱、最好能达到多少钱等等(protocol),而买家则必须达到这种要求(实现 protocol方法),神壕才会卖,否则他就不干。

    看完神壕卖房的例子,我想应该能大概理解 delegate 和 protocol 的关系了。

    举例个实际应用:

    /* 头文件 */
    /* 定义一个协议 */
    @protocol YHPhotoPickerViewControllerDelegate <NSObject>
    
    - (void)YHPhotoPickerViewController:(YHSelectPhotoViewController *)PhotoPickerViewController selectedPhotos:(NSArray *)photos;
    - (void)selectedPhotoBeyondLimit:(int)count currentView:(UIView *)view;
    
    @end
    
    @interface YHSelectPhotoViewController : UIViewController
    
    @property(weak, nonatomic) id<YHPhotoPickerViewControllerDelegate> pickerDelegate;
    
    @end
    

    实现方法:

    /* 实现类中的方法 */
    - (void)finshToSelectPhoto {
        
        if ([self.pickerDelegate respondsToSelector:@selector(YHPhotoPickerViewController:selectedPhotos:)]){
           // todo some thing
        }
    }
    

    在这里将数据交付出去。先判断delegate是否存在,然后再判断是否实现的协议的相关内容(若不实现需要crash时可以在判断里加上断言),当delegate 和 protocol 都实现了,就可以进行数据的交付了。

    调用方法:

    @interface ViewController : UIViewController <YHPhotoPickerViewControllerDelegate>
    
    #pragma mark - YHPhotoPickerViewController Delegate
    - (void)YHPhotoPickerViewController:(YHSelectPhotoViewController *)PhotoPickerViewController selectedPhotos:(NSArray *)photos {
        // handle data
    }
    
    @end
    

    这里处理交付的数据,需要实现协议方法

    Notification

    Notification,这东西又爱又恨,一不小心就坑到不要不要的,这里先不分析为什么,先说实现。Notification(观察者模式的一种实现) 和 Delegage 都是设计模块的一种,但是两种设计模式的使用场景不太一样。

    先看下观察者模式(图片来自大话设计模式):

    图片.png

    这里就不详细说设计模式,我看了下大话设计模式这本书,还是说得比较形象,有兴趣的可以看下,但我还是比较喜欢黑书那本。

    在 iOS 中,apple 已经封装好了 Notification,不需要我们实现,这里我们直接使用就可以了:

    发送通知:

    // object 就是交付的参数了,如果想传递多个参数时,可以使用集合来传递
    [[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:nil];
    

    再看上面,新手很容易被坑到,object 并不是交付的参数,看另一个接口:

    图片.png

    userInfo 才是要交付的参数,object 是用来做过滤通知的,_ 有没有坑过呢,问下自己吧。

    再看添加监听通知的方法:

    - (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject;
    

    这里也有objct,别纠结,直接看苹果 api 文档就好了:

    图片.png

    接收通知:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sensorStateChange:) name:UIDeviceProximityStateDidChangeNotification object:nil];
    
    - (void)sensorStateChange:(NSNotificationCenter *)notification { ... }
    

    其实苹果的api文档已经写得很详细了,如果有对接口方法有疑问,还是多去看下官方的接口文档。

    Block

    Block 可以理解为 OC 的匿名函数,也可以理解为 OC 中的一种特殊变量,它可以在两个对象之间将任意的代码块当做参数进行传递。

    举个例子:

    typedef void (^DictionaryResponseBlock)(NSDictionary *retDict);
    typedef void (^errorBlock)(NSError *error);
    
    + (void)reqeustWeatherInfo:(NSString *)cityName
                          successCallback:(DictionaryResponseBlock)successCallback
                             failCallback:(errorBlock)failCallback;
                             
    [XXXXX reqeustWeatherInfo:@"cityName" successCallback:^(NSDictionary *retDict) {
                    // 代码块(你要处理的操作)
                } failCallback:^(NSError *error) {
                    
                }];
    

    关键还是 在两个对象之间将任意的代码块当做参数进行传递 这句话的理解,上面的代码实行就是把

    ^(NSDictionary *retDict) {
                    // 代码块(你要处理的操作)
                }
    

    这些代码块当作参数传递到别一个对象中使用。在使用block的时候,初学的时候遇到过很懵逼的问题,就是什么时候使用weak,是否需要strong回来,看到唐巧大神的公众号有几篇文章解释得非常好,就是self 持有 block,block 又持有 self 时,就会引起循环引用,这个时候就需要使用:

    __weak __typeof(self)weakSelf = self;
    

    这种情况,为防止block调用self时,self被释放的情况,就要使用:

    __strong __typeof(weakSelf)strongSelf = weakSelf;
    
    if (strongSelf) {
    
    }
    

    详细可以去看巧神的公众号。

    KVO

    KVO(Key - Value - Observer) 又是观察者模式的一种实现,简单点说就是键值监听者,指定的对象的属性被修改后,监听的对象就会收到通知。

    举例:

    // 1.注册观察者
    [user addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:user.name];
    
    // 2.回调方法
    - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context {
    
    }
    
    // 3.移除观察者
    [user removeObserver:self forKeyPath:@"name"];
    
    }
    

    在这里可以通过context的值进行数据交付。

    Target-Action

    Target-Action(目标-动作模式),看起来有点抽象化,简单点来说就是:当某事件发生时,我们会xxx(目标,也可以说对象)的xxx方法(动作或行动)。

    最简的例子就是button的点击事件,这个就不单独举例了。

    选择何种交付方式

    其实对于选择何种交付方式,对我个人来说,这方面经验还是不足够,这里只介绍自己遇到的坑,有更好的建议的朋友望指点。

    合理使用Notification

    上面介绍过Notification时也说了,一不小心就坑得不要不要的,比如说你忘记把某个监听给移除了,这个就是很苦逼的事情,内心是很酸爽的。这个主要是编码不规范导致的。另一人主要原因还是Notification的影响面不可控制,没有办法确认处理地方法只有唯一,或者明确处理的地方,特别多人协助时就更加混乱。这里虽然说了Notification的使用很多不好的地方,但并不是强调Notification的不好,只有最合适的设计模式,没有好或者最坏的设计模式,所有能用的设计模式,都是前人的经验和总结,它们的存在都是经过了前人的检验的。比如网络状态的切换就很合适使用Notification。

    少用block

    其实能用block实现的东西都可以通过delegate来实现,但要区分怎么选择的话,那就是看回调的内容,如果回调要做的东西都是一致的就选择delegate;如果每次回调回来时要做的东西都不同,就选择block。

    block除了上面介绍的时候说过会可能导致循环引用,我们可以weak引用来解决这个方法,但block还是有可能延长了对象的生命周期,而delegate就不会有这种问题,因为它本身就是弱的引用。这里为什么说尽量少用block,主要还是因为深受其害啊,目前公司的项目,不管是在网络层还是业务层,清一色的block,刚才接手原来的项目时,每次调试到一半,我去,block,又一个block,又一个block,这个时候我们根本不知道block里做了什么只能一个个跳进去查看,发现里面又有block,内心是各种草泥马的,一个方法里面有几个block,block里面还有block,这代码可读性真的感觉为0,一个方法有1,2百行的代码,混合着各个不同的任务,方法的单一性呢。。。

    别一个问题,使用block的时候,回调的的代码和调用逻辑又放在一起了,很容易就出现那种一个方法几百行代码的情况,说好的方法单一性感觉又没有了。

    总结

    合理使用Notification,少用block。这里就只介绍这些了,其它的在后面的学习有所体会时再来补充了,如果有更好见解的朋友,望指出,大家多分享交流。

    相关文章

      网友评论

      • Eve_wang:为什么要少用block
        YxxxHao:@sara_xuehua 主要是不要滥用,大量使用block在实现开发中,最明显的一上缺点就是出了问题之后调试很坑逼
        Eve_wang:@YxxxHao 使我们用的不正确,还是block本来就有缺点
        YxxxHao:@sara_xuehua 文中已经说了啊

      本文标题:关于 iOS 中数据交付

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