美文网首页
iOS知识梳理3:设计模式

iOS知识梳理3:设计模式

作者: 大布溜 | 来源:发表于2017-08-29 17:45 被阅读59次

    iOS有哪些常见的设计模式?
    单例模式/委托模式/观察者模式/MVC模式


    单例模式

    单例保证了应用程序的生命周期内仅有一个该类的实例对象,而且易于外界访问.

    在ios sdk中,UIApplication, NSBundle, NSNotificationCenter, NSFileManager, NSUserDefault, NSURLCache等都是单例.

    在实际开发中,单例一般会分为ARC和非ARC两种不同的写法,这些代码可以通过判断统一整理到PCH文件中,这样每次使用单例时就不用多次输入重复的代码.

    单例的代码简单样例:

    //.h
    @interface Singleton:NSObject
    +(Singleton *)sharedManager;
    @property(nonatomic,strong)NSString *singletonData;
    @end
    
    //.m
    #import "Singleton.h"
    @implementation Singleton
    
    static Singleton *sharedManager = nil;
    
    +(Singleton *)sharedManager
    {
         static dispatch_once_t once;
        dispatch_once(&once,^{
                sharedManager = [[self alloc] init];
         });
        return sharedManager;
    }
    @end
    

    委托模式

    委托Delegate是协议的一种,通过@protocol方式实现. 顾名思义, 就是委托他人帮自己去做什么事. 也就是当自己不方便做什么事情的时候, 就可以建立一个委托, 这样就可以委托他人帮忙去做.

    比如常见的UITableView, iOS SDK在写这个类的时候,肯定不知道开发者想要在点击某一行之后都要进行什么操作, 所以只好让程序员委托UIViewController去代理UITableViewDelegate来实现这个方法.

    同样的,它也不知道开发者希望这个表有多少行,每个cell的内容都是什么样的,所以UITableView只好委托UIViewController去代理他的UITableViewDataSource来实现这些方法.

    当然,代理方法一是可以传递事件, 二也可以用来传递值,
    比如:tableview的datasource里的一个代理方法

    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    

    委托者可以把行数通过indexpath传递给被委托者,被委托者取到行数之后,自定义如何表现这个cell,再把cell传回给委托者.

    下面有用一个Man类的例子来详细解说一下.
    Man类,可以初始化一个胖子或瘦子,然后完成他的早中晚的一天......然后吃饭工作睡觉之后都干什么他自己不知道.....只好告诉你他吃了什么,睡了多久 ,让你来帮他决定.....我瞎编的...你也许可以编一个好一点的....

    //man.h
    #import <Foundation/Foundation.h>
    
    //*************** delegate ***********************
    //创建代理.吃喝工作的结果让别人帮你完成,你只需要提供吃了啥,睡了多久就行了.
    @protocol ManDelegate <NSObject>
    
    @required
    //人可以吃不睡,但是一定要工作啊....所以required
    -(void)work;
    
    @optional
    //返回一个睡觉的时间给被委托的对象,通过这个时间来处理相关事宜
    -(void)sleepWithTime:(int)time;
    //通过给被委托者一种食物,返回一个布尔值,来判断是否吃饱.
    -(BOOL)eatWithFood:(NSString *)food;
    
    @end
    //*************** delegate ***********************
    @interface Man : NSObject
    
    //delegate属性
    @property (nonatomic, weak) id<ManDelegate> delegate;
    
    //是胖,是瘦呢,这个在实例化类的时候完成.
    @property (nonatomic, assign) BOOL isFat;
    
    //你这一天都分别干了啥,这个要你自己完成
    -(void)morning;
    -(void)afternoon;
    -(void)everning;
    
    @end
    
    //man.m
    #import "Man.h"
    @implementation Man
    
    //通过[self.delegate XXXX]确定代理出去的方法在自己的方法里的实现的位置;
    
    //早上睡了7个小时.吃了点面包,没吃饱就不工作,吃饱了就接着工作..
    -(void)morning{
        [self.delegate sleepWithTime:7];
        BOOL isFull = [self.delegate eatWithFood:@"面包"];
        //觉得面包吃饱了就工作,面包吃不饱就不工作.
        if(isFull == YES){
            NSLog(@"早饭吃饱了,工作");
            [self.delegate work];
        }
        else{
            NSLog(@"早饭吃饱了,不工作");
        }
    }
    
    //中午睡了1个小时,睡完接着工作.
    -(void)afternoon{
        [self.delegate sleepWithTime:1];
        [self.delegate work];
    }
    
    
    //晚上睡了3个小时...
    -(void)everning{
        [self.delegate sleepWithTime:3];
    }
    @end
    
    //代理执行的位置
    #import "ViewController.h"
    #import "Man.h"
    
    @interface ViewController ()<ManDelegate>
    
    @property (nonatomic,retain) Man *zhangsan;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        //初始化一个张三实例,张三不胖.
        self.zhangsan = [[Man alloc] init];
        self.zhangsan.isFat = NO;
        
        //把张三工作/吃/睡之后要干嘛,交给self也就是ViewController来决定,就是实现代理方法
        self.zhangsan.delegate = self;
    
        //张三的一天.
        [self.zhangsan morning];
        [self.zhangsan afternoon];
        [self.zhangsan everning];
    }
    
    #pragma mark ----ManDelegate
    //viewcontroller决定,让张三工作的时候打印一句话到控制台.
    -(void)work{
        NSLog(@"Working");
    }
    
    //viewcontroller决定,根据张三提供来的休息时间,把他的休息情况打印到控制台上.
    -(void)sleepWithTime:(int)time
    {
        NSLog(@"Slept for %d hour",time);
        if(time>4){
            NSLog(@"长眠不起");
        }else if(time == 4){
            NSLog(@"不长不短");
        }else if(time < 4){
            NSLog(@"小眯一下");
        }
    }
    
    //viewcontroller决定,通过张三提供吃的食物的内容,来判断张三是不是吃饱了...并且返回给张三...让他自己通过判断自己饱了没饱来处理一些事情
    -(BOOL)eatWithFood:(NSString *)food{
        if (self.zhangsan.isFat == YES && [food isEqualToString:@"面包"]) {
            return NO;
        }
        else if(self.zhangsan.isFat == NO && [food isEqualToString:@"面包"]){
            return YES;
        }
        else{
            return YES;
        }
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    @end
    
    
    问题1:为什么delegate作为属性需要是weak?

    防止retain cycle循环引用...
    比如tableview....UIViewCotroller通过self.view addsubview.已经指向tableview了......所以tableview.delegate = self 和tableview.datasource又指向了viewcontroller,如果此时delegate是strong,就会发生循环引用无法释放,所以这里应该是weak.....详细见上一章属详解.

    观察者模式

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 简而言之,就是A和B,A对B的变化感兴趣,就注册为B的观察者,当B发生变化时通知A,告知B发生了变化。这个也叫做经典观察者模式。

    在iOS中,观察者模式的具体实现有两种: 通知机制(notification)和KVO机制(Key-value Observing)

    1.通知机制

    注册通知接收者的代码:

    [[NSNotificationCenter DefaultCenter] addObserver:self
                                            selector:@selector(registerCompeletion:)
                                               name:@"RigsterCompletionNotification"
                                              object:nil];
    
    -(void)registerCompletion:(NSNotification *)notification{
          NSDictionary *theData = [notification useInfo];
          NSString *username = [theData objectForKey:@"username"];
          NSLog(@"username = %@",username);
    }
    

    投送通知的代码

    NSDictionary *dataDic = [NSDictionary dictionaryWithObject:self.text
                                                        forkey:@"username"];
    [[NSNotificationCenter DefaultCenter] postNotificationName:@"RegisterCompeletionNotification"
                                                        object:nil
                                                      userInfo:dataDict];
    
    问题1. object是干嘛的?是不是可以用来传值?

    答:object是用来过滤Notification的,只接收指定的sender所发的Notification.....传值请用userInfo,而不是object

    问题2. iOS中,广播通知(broadcast notification)/本地通知(local notification)/推送通知(push notification)有什么区别和不同?

    出了名字相似以外,广播通知和其他两个通知是完全不一样的: 广播通知是cocoatouch中观察者模式的一种机制, 实现应用内部多个对象的通信...本地通知和推送通知中的"通知"是一种"提示"...通过警告框,发出声音,振动和在应用图标上显示数组等,在计划时间到达时,本地通知通过本地iOS发出,推送通知由第三方程序发送给苹果远程服务器,再由远程服务器推送给iOS特定应用.

    2.KVO机制

    对象的属性变化时,通知会直接发送到观察者对象.

    可以用来实现 ,比如, UITableView滑动时导航自动变换颜色,或者,一个计算房贷的软件,当首付金额改变时,每月还款数目等数据相应自动改变等.

    这里来观察UITableView一个实例的contentOffset属性.

    //添加监听者
    [self.tableView addObserver:self    //监听者
                    forKeyPath:@"contentOffset"  //被观察对象的属性字符串
          options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//设置.这里的设置表示把属性变换的新旧两个值都传递给观察者
                       context:nil];//上下文内容,c语言形式的任何指针类型
    
    //监听属性变化时的回调
    -(void)obserValueForKeyPath:(NSString *)keyPath   //被观察的属性
                       ofObject:(id)object   //被观察的对象
                         change:(NSDictionary *)change//字典类型包含了变化的内容,与options呼应
                        context:(void *)context//传递过来的上下文
    {
                 NSLog(@"%@-%@",keyPah, (NSString *)change[NSKeyValueChangeNewKey]);//通过change字典渠道变化的属性变化前或变化后的值.
    }
    

    相关文章

      网友评论

          本文标题:iOS知识梳理3:设计模式

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