zoukankan      html  css  js  c++  java
  • iOS,几种设计模式

    1.单例模式

    2.观察者模式

    3.委托代理

    4.block回调

    5.反射机制

    6.多代理模式

    单例模式

    iOS单例模式的2种方式。根据线程安全的实现来区分,一种是使用@synchronized ,另一种是使用GCD的dispatch_once函数。

    要实现单例,首先需要一个static的指向类本身的对象,其次需要一个初始化类函数。下面是两种实现的代码。

    @synchronized

    static InstanceClass *instance;
    + (InstanceClass *)shareInstance{
        @synchronized (self){
            if (instance == nil) {
                instance = [[InstanceClass alloc] init];
            }
        }
        return instance;
    }

    GCD

    static InstanceClass *instance;
    + (InstanceClass *)shareInstance{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[InstanceClass alloc] init];
        });
        return instance;
    }

    示例:

    +(MyClass *)shareInstance
    {
        static dispatch_once_t once;
        static id instance;
        dispatch_once(&once, ^{
            instance = [[self alloc]init];
        });
        return instance;
    }

    观察者模式

    Notification(通知)

    //向通知中心添加消息监听名称,和通知方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDisappear:) name:@"DismissFaceVerifyController" object:nil];
    
    //通过通知中心调用对应消息名
    [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissFaceVerifyController" object:self userInfo:nil];

    KVO(键值监听),即Key-Value Observing

    监听对象的属性(成员变量)变化,对象可以是自己也可以是其它

    //实例监听自己的属性

    //ViewController.m文件

    //
    //  ViewController.m
    //  KVOLearn
    //
    //  Created by Vie on 2017/4/6.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    
    #import "ViewController.h"
    
    @interface ViewController ()
    @property(strong, nonatomic) NSString *testStr;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        
        self.testStr=@"Tracer";
        
        //按钮
        UIButton *loginBtn=[[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2-50, 350, 100, 50)];
        [loginBtn setTitle:@"改变值" forState:UIControlStateNormal];
        [loginBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [loginBtn setBackgroundColor:[UIColor redColor]];
        [loginBtn.layer setBorderWidth:0.2f];
        [loginBtn.layer setCornerRadius:10.0f];
        [loginBtn addTarget:self action:@selector(changeAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:loginBtn];
        
        /*1.注册对象self为被观察者: option中,
         forKeyPath为被观察的对象属性
         NSKeyValueObservingOptionOld 以字典的形式提供 “初始对象数据”;
         NSKeyValueObservingOptionNew 以字典的形式提供 “更新后新的数据”; */
        [self addObserver:self forKeyPath:@"testStr" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
    }
    //按钮事件
    -(void)changeAction:(UIButton *)sender{
        self.testStr=@"Vie";
    }
    
    /* 只要object的keyPath属性发生变化,就会调用此回调方法*/
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        if ([keyPath isEqualToString:@"testStr"]) {
            NSLog(@"监听到testStr属性值改变");
        }
    }
    -(void)dealloc{
        //移除self中forKeyPath属性观察
        [self removeObserver:self forKeyPath:@"testStr" context:nil];
    }
    
    
    @end

     

    委托代理

    delegate

    委托应用场景:一个view把一些业务交给 控制器去实现,然后控制器实现委托改变view 

    //在ViewController.h中声明协议如下 

    @protocol ByValueDelegate <NSObject> 
    -(void) passValue:(NSString *) value;
    @end 

    //在ViewController.h中声明委托变量 

    @property (nonatomic,weak) id<ByValueDelegate> delegate;//声明一个委托变量 

    //在ViewController.m中设置代理 

    UserinfoView *uiv=[[UserinfoView alloc]init]; 
    //把值委托到UserinfoView.m的实现委托的方法里面 
    self.delegate=uiv;//设置该对象代理为对象uiv 
    [self.delegate passValue:@"委托传值跳转"]; 





    //在UserinfoView.h中,引用ViewController的头文件,并添加代理协议如下 

    #import "ViewController.h" 
    
    @interface UserinfoView : UIViewController<ByValueDelegate>@property (nonatomic,strong) UILabel *showLable; 
    @property (nonatomic,retain) UserinfoEntity *showUserinfoEntity; 
    -(void) viewDidLoad;@end 


    //在UserinfoView.m中实现代理函数 

    //实现委托方法 
    -(void) passValue:(NSString *)value{
       UIAlertView *alterOk = [[UIAlertView alloc] initWithTitle:@"提示" message:value delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil]; 
       [alterOk show]; 
    }

    KVC(键值编码),即Key-Value Coding,一个非正式的Protocol,使用字符串(键)访问一个对象实例变量的机制

    就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态在访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。

    KVC在iOS中的定义
    
    无论是Swift还是Objective-C,KVC的定义都是对NSObject的扩展来实现的(Objective-c中有个显式的NSKeyValueCoding类别名,而Swift没有,也不需要)所以对于所有继承了NSObject在类型,都能使用KVC(一些纯Swift类和结构体是不支持KVC的),下面是KVC最为重要的四个方法
    //KVC最为重要的四个方法
    
    - (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
    - (void)setValue:(nullable id)value forKey:(NSString *)key;          //通过Key来设值
    - (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通过KeyPath来取值
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值

     //例

    //PersonInfoModel.h文件

    //
    //  PersonInfoModel.h
    //  KVCLearn
    //  个人信息
    //  Created by Vie on 2017/4/6.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface PersonInfoModel : NSObject
    @property(strong, nonatomic) NSString *name;//姓名
    @property(strong, nonatomic) NSString *gender;//性别
    @property(assign, nonatomic) NSNumber *age;//年龄
    @end

    //StudentInfoModel.h文件

    //
    //  StudentInfoModel.h
    //  KVCLearn
    //  学生信息
    //  Created by Vie on 2017/4/6.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "PersonInfoModel.h"
    @interface StudentInfoModel : NSObject
    @property(strong, nonatomic)PersonInfoModel *personModel;//个人信息
    @property(strong, nonatomic)NSString *studentID;//学号
    @property(strong, nonatomic)NSString *departments;//院系
    @end

    //使用

    #import "StudentInfoModel.h"
    
    
    
     StudentInfoModel *studentModel=[[StudentInfoModel alloc] init];
     //设值
     [studentModel setValue:@"信息技术学院" forKey:@"departments"];
     [studentModel setValue:@"Vie" forKeyPath:@"personModel.name"];
     //取值
     NSLog(@"%@",[studentModel valueForKey:@"departments"]);
     NSLog(@"%@",[studentModel valueForKeyPath:@"departments"]);

    修改系统控件内部属性(runtime + KVC)

    将UIPageControl样式原来样式

    修改为下面

     

    PageControl公开属性没有直接可以修改的,目前可以自定义PageControl,这种方式看起来不简单。另一种方式就是,通过runtime遍历出UIPageControl所有属性(包括私有成员属性,runtime确实很强大)。

     //遍历属性
          unsigned int count = 0;
          Ivar *ivars = class_copyIvarList([UIPageControl class], &count);
          for (int i = 0; i < count; i++) {
              Ivar ivar = ivars[i];
              //获取所有私有属性
              const char *property = ivar_getName(ivar);
              NSLog(@"%@",[[NSString alloc]initWithCString:property encoding:NSUTF8StringEncoding]);
          }

    //运行结果

    2017-04-06 20:12:20.756 KVCLearn[4430:220644] _lastUserInterfaceIdiom
    2017-04-06 20:12:20.756 KVCLearn[4430:220644] _indicators
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _currentPage
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _displayedPage
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _pageControlFlags
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _currentPageImage
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _pageImage
    2017-04-06 20:12:20.757 KVCLearn[4430:220644] _currentPageImages
    2017-04-06 20:12:20.758 KVCLearn[4430:220644] _pageImages
    2017-04-06 20:12:20.758 KVCLearn[4430:220644] _backgroundVisualEffectView
    2017-04-06 20:12:20.758 KVCLearn[4430:220644]_currentPageIndicatorTintColor
    2017-04-06 20:12:20.758 KVCLearn[4430:220644] _pageIndicatorTintColor
    2017-04-06 20:12:20.758 KVCLearn[4430:220644] _legibilitySettings
    2017-04-06 20:12:20.758 KVCLearn[4430:220644] _numberOfPages

    //找到了属性后,接着实现

    //然后通过KVC设置自定义图片,实现了效果,代码如下:
     UIPageControl *pageControl = [[UIPageControl alloc] init]; 
     [pageControl setValue:[UIImage imageNamed:@"home_slipt_nor"] forKeyPath:@"_pageImage"];
     [pageControl setValue:[UIImage imageNamed:@"home_slipt_pre"] forKeyPath:@"_currentPageImage"];

    block回调

        

         block中使用修改方法外的属性需要用__block修饰,例如:

    __block BOOL whoopsSomethingWrongHappened = true;

    //ViewController.m文件
    #import "ViewController.h"
    #import "CallbackTest.h"
    @interface ViewController ()
    
    @end
     
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        [self.view setBackgroundColor:[UIColor whiteColor]];
        UIButton *backBtn=[[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width*0.4, self.view.frame.size.height*0.475, self.view.frame.size.width*0.2, self.view.frame.size.height*0.05)];
        [backBtn.layer setCornerRadius:5.0];
        [backBtn setTitle:@"回调" forState:UIControlStateNormal];
        [backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [backBtn.layer setBorderWidth:0.5];
        [backBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:backBtn];
    }
    
    /**
     *  @Author Vie, 2015-08-05 13:41:37
     *  使用block回调函数
     *  @param sender sender description
     *
     *  @since <#version number#>
     */
    -(void)btnAction:(UIButton *)sender{
        CallbackTest *backTest=[[CallbackTest alloc] init];
        //第一种回调方式
    //    [backTest startString:@"回调开始" callBack:^(NSString *backFunstring) {
    //     回调时候会执行
    //        UIAlertView  *alert=[[UIAlertView alloc] initWithTitle:@"回调提示" message:backFunstring delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
    //        [alert show];
    //
    //    }];
    
       
        //第二种回调方式
        backTest.backCall=^(NSString *string){
            UIAlertView  *alert=[[UIAlertView alloc] initWithTitle:@"回调提示"message:string delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
            [alert show];
        };
        [backTest blockCall:@"回调开始"];
    }
    @end
    //CallbackTest.h文件
    #import <UIKit/UIKit.h>
    @interface CallbackTest : NSObject
    //定义一个block,返回值为void,参数为NSString
    typedef void(^backFunction)(NSString *backFunstring);
    @property (nonatomic,copy) backFunction backCall;
    -(void)startString:(NSString *)str callBack:(backFunction)backString;
    -(void)blockCall:(NSString *)str;//第一一个block属性
    @end

     

    //CallbackTest.m文件
    #import "CallbackTest.h"
     
    @implementation CallbackTest
    //第一种回调方式
    -(void)startString:(NSString *)str callBack:(backFunction)backString{
        NSMutableString *mutString=[str mutableCopy];
        [mutString appendString:@"回调完成"];
        //执行block
    //    backString(mtuString);
         //将block回调交给另一个方法执行
        [self TestBackCall:mutString callBack:backString];
    }
    
    //执行block回调的函数
    -(void)TestBackCall:(NSMutableString *)mutString callBack:(backFunction)testBack{
        testBack(mutString);
    }
    
    //第二种回调方式
    -(void)blockCall:(NSString *)str{
        NSMutableString *mutString=[str mutableCopy];
        [mutString appendString:@"回调完成"];
        _backCall(mutString);
    }
    @end

    反射机制

    //使用NSClassFromString,通过字符串获取类 
    Class class=NSClassFromString(@"UIAlertView");
    //或者使用objc_getClass,通过字符串获取类 
    //Class class=objc_getClass("UIAlertView");
    id  alert=  [[class alloc] initWithTitle:@"123" message:@"111" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
    [alert show];

    多代理模式

      使用NSPointerArray进行多代理可以跟踪内存,它是mutable,数组不会增加这个对象的引用计数

    //例

    //MoreDelegate.h文件

    //
    //  MoreDelegate.h
    //  MoreDelegate
    //  委托
    //  Created by Vie on 2017/5/2.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    @protocol MoreDelegate <NSObject>
    
    @optional
    -(void)testMoreDelegate;//多代理测试
    
    @end

    //后面可以结合通知(或者其他方式)使用,到达方法准确调用带参。

    //MoreDelegateManager.h文件

    //
    //  MoreDelegateManager.h
    //  MoreDelegate
    //  多代理管理实现类
    //  Created by Vie on 2017/5/2.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import "MoreDelegate.h"
    
    @interface MoreDelegateManager : NSObject
    
    
    /**
     单例模式
     
     @return self
     */
    +(MoreDelegateManager *)shareInstance;
    
    /**
     注册代理
     
     @param obj 需要实现代理的对象
     */
    -(void)registerDelegate:(id)obj;
    
    
    /**
     解除代理
     
     @param obj 需要接触代理的对象
     */
    -(void)unRegisterDelegate:(id)obj;
    
    
    /**
     执行代理方法(后续可以多个方法提供出去,方便传参调用)
    
     @param aSelector 类方法选择器
     */
    -(void)delegateAction:(SEL)aSelector;
    @end

    //MoreDelegateManager.m文件

    //
    //  MoreDelegateManager.m
    //  MoreDelegate
    //
    //  Created by Vie on 2017/5/2.
    //  Copyright © 2017年 Vie. All rights reserved.
    //
    
    #import "MoreDelegateManager.h"
    
    
    #import <objc/runtime.h>
    #import <objc/message.h>
    
    @interface MoreDelegateManager ()<MoreDelegate>
    @property(nonatomic,strong) NSPointerArray *delegateArr;//实现委托的数组
    @end
    
    @implementation MoreDelegateManager
    #pragma mark 懒加载
    -(NSPointerArray *)delegateArr{
        if (!_delegateArr) {
            _delegateArr=[NSPointerArray weakObjectsPointerArray];
        }
        return _delegateArr;
    }
    
    #pragma mark 对外方法
    /**
     单例模式
     
     @return self
     */
    +(MoreDelegateManager *)shareInstance{
        static id instanc;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instanc=[[self alloc] init];
        });
        return instanc;
    }
    /**
     注册代理
     
     @param obj 需要实现代理的对象
     */
    -(void)registerDelegate:(id)obj{
        NSLog(@"注册代理类:%@",NSStringFromClass([obj class].class));
        [self.delegateArr addPointer:(__bridge void*)obj];
    }
    
    
    /**
     解除代理
     
     @param obj 需要接触代理的对象
     */
    -(void)unRegisterDelegate:(id)obj{
        NSLog(@"解除注册代理类:%@",NSStringFromClass([obj class].class));
        NSUInteger index=[self indexOfDelegte:obj];
        if (index!=NSNotFound) {
            [self.delegateArr removePointerAtIndex:index];
        }
        //去掉数组里面的野指针
        [self.delegateArr compact];
    }
    
    /**
     执行代理方法
     
     @param aSelector 类方法选择器
     */
    -(void)delegateAction:(SEL)aSelector{
        for (id delegate in self.delegateArr) {
            if (delegate&&[delegate respondsToSelector:aSelector]) {
    //            ((void (*) (id, SEL)) objc_msgSend) (delegate, aSelector);
                [delegate testMoreDelegate];
            }
        }
    }
    
    #pragma mark 内部使用方法
    
    /**
     计算Delegate的下标
    
     @param obj 代理委托类
     @return 下标
     */
    -(NSUInteger)indexOfDelegte:(id)obj{
        for (NSUInteger i=0; i<self.delegateArr.count; i++) {
            if ([_delegateArr pointerAtIndex:i]==(__bridge void*)obj) {
                return i;
            }
        }
        return NSNotFound;
    }
    @end

    //使用

    //在几个不同的控制器中注册代理
    [[MoreDelegateManager shareInstance] registerDelegate:self];
    
    
    //调用事件
    [[MoreDelegateManager shareInstance] delegateAction:@selector(testMoreDelegate)];
    
    //实现委托方法
    -(void)testMoreDelegate{
        NSLog(@"代理实现类:%@",NSStringFromClass(self.class));
    }
  • 相关阅读:
    dropload.js 上滑加载,下拉刷新
    jQuery支持图片放大缩小查看效果
    iScroll-5 API 中文版
    多行文字垂直居中
    jQuery延迟加载(懒加载)插件 – jquery.lazyload.js
    js生成中文二维码
    JS中,如何判断一个数是不是小数?如果是小数,如何判断它是几位小数??
    HTML5页面,用JS 禁止弹出手机键盘
    watch和computed的用法区别是什么?
    JS中的call()和apply()
  • 原文地址:https://www.cnblogs.com/douniwanxia/p/5896396.html
Copyright © 2011-2022 走看看