ios开发中的几种设计模式

    xiaoxiao2021-03-25  104

    一,单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。

    /**

     static : 修饰变量

     1> 修饰全局变量

     * 全局变量的作用域仅限于当前文件内部(不加的话别人使用extern关键字就能从其他文件访问这个文件的全局变量了)

     2> 修饰局部变量 :

      * 能保证局部变量永远只初始化1次,在程序运行过程中,永远只有1分内存

     * 局部变量的生命周期全局变量类似

     * 但是不能改变作用域

     */

    #pragma mark 懒汉式单例 arc

    #import "HMMusicTool.h"

    @implementation HMMusicTool

    static id _instance; //保证这个全局变量只能当前文件可以访问

    /**

     *  alloc方法内部会调用这个方法

     */

    + (id)allocWithZone:(struct _NSZone *)zone

    {

        if (_instance ==nil) { //防止频繁加锁

            @synchronized(self) {

                if (_instance ==nil) { //防止创建多次

                    _instance = [super allocWithZone:zone];

                }

            }

        }

        return _instance;

    }

    + (instancetype)sharedMusicTool

    {

        if (_instance ==nil) { //防止频繁加锁

            @synchronized(self) {

                if (_instance ==nil) { //防止多次init

                    _instance = [[self alloc] init];

                }

            }

        }

        return _instance;

    }

    //copy方法内部会调用这个方法

    - (id)copyWithZone:(NSZone *)zone

    {

        return _instance;//保证copy方法调用之后也是这一个对象不会产生新的对象,因为copy可能拷贝产生新的对象

    }

    @end

      饿汉式 (不需要掌握)

    //#import "HMSoundTool.h"

    //@implementation HMSoundTool

    //

    //static id _instance;

    //

    ///**

    // *  当类加载到OC运行时环境中(内存),就会调用一次(一个类只会加载1次)

    // */

    //+ (void)load

    //{

    //    _instance = [[self alloc] init];

    //}

    //

    //+ (id)allocWithZone:(struct _NSZone *)zone

    //{

    //    if (_instance == nil) { // 防止其他创建多次

    //        _instance = [super allocWithZone:zone];

    //    }

    //    return _instance;

    //}

    //

    //+ (instancetype)sharedSoundTool

    //{

    //    return _instance;

    //}

    //

    //- (id)copyWithZone:(NSZone *)zone

    //{

    //    return _instance;

    //}

    //

    /**

    当第一次使用这个类的时候才会调用 (如果使用这个类的方法还需要调用父类的这个方法,比如继承,那么弗雷德initialize方法也会调用)load的区别就在这

    */

    + (void)initialize

    {

        NSLog(@"HMSoundTool---initialize");

    }

    //@end

    #pragma mark GCD模式单例  arc

    #import <Foundation/Foundation.h>

    @interface HMDataTool : NSObject

    + (instancetype)sharedDataTool;

    @end

    #import "HMDataTool.h"

    @implementation HMDataTool

    // 用来保存唯一的单例对象

    static id _instace;

    + (id)allocWithZone:(struct _NSZone *)zone

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [super allocWithZone:zone];

        });

        return _instace;

    }

    + (instancetype)sharedDataTool

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [[self alloc] init];

        });

        return _instace;

    }

    - (id)copyWithZone:(NSZone *)zone

    {

        return _instace;

    }

    @end

    #pragma mark GCD单例模式arc

    #import "HMDataTool.h"

    @implementation HMDataTool

    // 用来保存唯一的单例对象

    static id _instace;

    + (id)allocWithZone:(struct _NSZone *)zone

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [super allocWithZone:zone];

        });

        return _instace;

    }

    + (instancetype)sharedDataTool

    {

        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{

            _instace = [[self alloc] init];

        });

        return _instace;

    }

    - (id)copyWithZone:(NSZone *)zone

    {

        return _instace;

    }

    //arc多了这几个方法

    - (onewayvoid)release{

    }

    - (id)retain {

        returnself;

    }

    - (NSUInteger)retainCount {

        return1;

    }

    - (id)autorelease {

        returnself;

    }

    @end

    #pragma mark 宏实现单例,自定义名称,适配arc和非arc

    创建一个HMSingleton.h文件,.h文件中写以下宏

    // .h文件

    #define HMSingletonH(name) + (instancetype)shared##name;

    // .m文件

    #if __has_feature(objc_arc)

    #define HMSingletonM(name) \

    static id _instace; \

    \

    + (id)allocWithZone:(struct _NSZone *)zone \

    { \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

    _instace = [super allocWithZone:zone]; \

    }); \

    return _instace; \

    } \

    \

    + (instancetype)shared##name \

    { \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

    _instace = [[self alloc] init]; \

    }); \

    return _instace; \

    } \

    \

    - (id)copyWithZone:(NSZone *)zone \

    { \

    return _instace; \

    }

    #else

    #define HMSingletonM(name) \

    static id _instace; \

    \

    + (id)allocWithZone:(struct _NSZone *)zone \

    { \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

    _instace = [super allocWithZone:zone]; \

    }); \

    return _instace; \

    } \

    \

    + (instancetype)shared##name \

    { \

    static dispatch_once_t onceToken; \

    dispatch_once(&onceToken, ^{ \

    _instace = [[self alloc] init]; \

    }); \

    return _instace; \

    } \

    \

    - (id)copyWithZone:(NSZone *)zone \

    { \

    return _instace; \

    } \

    \

    - (oneway void)release { } \

    - (id)retain { return self; } \

    - (NSUInteger)retainCount { return 1;} \

    - (id)autorelease { return self;}

    #endif

    再把HMSingleton.h文件导入pch文件即可

    使用的时候就在需要使用的类的.h文件中加一句HMSingletonH .m文件加一句HMSingleton.m即可

    二,观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。

    //1.KVC

    #pragma mark -KVC

    - (void)viewDidLoad

    {

        [super viewDidLoad];

        XLCustom * custom = [[XLCustom alloc]init];

        //<1>

        //原始方法对成员变量进行赋值使用的是setter方法或者点语法

        //原始方法对成员变量进行获取使用的是getter方法或者点语法

        //    custom.name = @"xuli";

        //    [custom setAge:19];

        //    NSLog(@"%@,%d",[custom name],custom.age);

        //[结论]原始方法对成员变量进行赋值和获取前提是该成员变量必须具有settergetter方法的声明和实现部分

        //<2>KVC

        //KVC key-value-coder的缩写 键值编码的简称

        //KVC -------- 对象的属性或者成员变量进行赋值进行赋值(私有的也可以修改),一般用来替换系统的私有的东西

        /*

         1、先去类中查找是否具有该变量的setter方法的声明和实现部分 如果具有直接调用setter方法对成员变量进行赋值

         2、如果不具有 继续查找是否具有以该变量命名的成员变量 如果具有直接赋值

         3、如果不具有 继续查找是否具有以下划线开头以变量命名的成员变量 如果具有直接赋值 如果不具有崩溃

         */

        //KVC 对成员变量进行赋值使用的方法是setValue:forkey(path): 前提是找到赋值的类的对象的指针

        [custom setValue:@"xuli" forKey:@"name"];

        [custom setValue:@(19) forKey:@"age"];

        //KVC 对成员变量进行获取使用的方法的是valueForkey(path):

        NSLog(@"%@,%d",[custom valueForKey:@"name"],[[custom valueForKey:@"age"] intValue]);

        //1.KeyPathKey的区别

        Person *p = [[Person alloc] init];

        p.dog = [[Dog alloc] init];

        p.dog.bone = [[Bone alloc] init];

        //        p.dog.bone.type = @"狗骨";

        

        //        [p setValue:@"猪骨" forKeyPath:@"dog.bone.type"];

        //        [p.dog setValue:@"猪骨" forKeyPath:@"bone.type"];

        [p.dog.bone setValue:@"猪骨" forKeyPath:@"type"];

        

        NSLog(@"%@", p.dog.bone.type);

        

        //        p.dog.name = @"wangwang";

        //        [p.dog setValue:@"wangcai" forKey:@"name"];

        //        [p.dog setValue:@"larry" forKeyPath:@"name"];

        

        //        [p setValue:@"hashiqi" forKeyPath:@"dog.name"];

        

        //forKeyPath包含了forKey的功能,以后使用forKeyPath就可以了

        //forKeyPath中可以利用.运算符, 就可以一层一层往下查找对象的属性

        //        [p setValue:@"hashiqi" forKey:@"dog.name"]; // 写法错误

        

        //        NSLog(@"%@", p.dog.name)

        //2.关于KVC中的数据数组 (不常用,知道就好)

        Person *p = [[Person alloc] init];

        Book *book1 = [[Book alloc] init];

        book1.name = @"5分钟突破iOS开发";

        book1.price = 10.5;

        Book *book2 = [[Book alloc] init];

        book2.name = @"5分钟突破android开发";

        book2.price = 18.5;

        Book *book3 = [[Book alloc] init];

        book3.name = @"5分钟突破前端开发";

        book3.price = 20.5;

        Book *book4 = [[Book alloc] init];

        book4.name = @"5分钟突破PHP开发";

        book4.price = 10.5;

        p.books = @[book1, book2, book3, book4];

        

        // 获得所有的书名(将所有的书名放到一个数组中)

        //        NSMutableArray *names = [NSMutableArray array];

        //        for (Book *book in p.books) {

        //            [names addObject:book.name];

        //        }

        

        // 取出books数组中每一个元素的name属性值,放到一个新的数组中返回

        NSArray *names = [p valueForKeyPath:@"books.name"];

        [p valueForKeyPath:@"dog.name"];

        NSLog(@"%@", names);

        //取出数组中的books的价格,再把每一个价格加起来 返回值是NSNumber类型的数据

        //NSNumber *avgNumber = [p valueForKeyPath:@"books.@avg.price"]; 求平均值

        NSNumber *sumNumber = [p valueForKeyPath:@"books.@sum.price"];//求和

        NSLog(@"%@", sumNumber);

        //        NSLog(@"%f", [sumNumber doubleValue]);

    }

    // 2. 使用KVC进行正向和反向传值

    //正向传值:给下一个界面设一个属性来接受传过去的值,在这个界面获取下一个界面的指针,用指针[next setValue:[UIColor magentaColor] forKey:@"nextColor"];

    //反向传值:在上一个界面设置一个属性接受传过来得值,在下一个界面设一个属性id delegate; 设置下一个界面的属性是上一个界面的指针.然后用代理(即上一个界面的指针)设置上一个界面的属性值,这样就反向传过去了

    // 3. KVO 的使用

    #pragma mark - KVO

    #import "XLViewController.h"

    #import "XLBoy.h"

    #import "XLGirl.h"

    @interface XLViewController ()

    {

        XLBoy * boy;

        XLGirl * girl;

    }

    @end

    @implementation XLViewController

    -(void)createUI

    {

        NSArray * array = @[@"

    转载请注明原文地址: https://ju.6miu.com/read-19342.html

    最新回复(0)