美文网首页GXiOS
iOS开发--拷贝及单例模式

iOS开发--拷贝及单例模式

作者: Caesar_62dd | 来源:发表于2019-05-09 12:52 被阅读3次

    1.Copy的使用

    • 如何使用copy功能
      • 一个对象可以调用copy或mutableCopy方法来创建一个副本对象
      • copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
      • mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
    • 使用copy功能的前提
      • copy : 需要遵守NSCopying协议,实现copyWithZone:方法
    @protocol NSCopying
    - (id)copyWithZone:(NSZone *)zone;
    @end
    
    • 使用mutableCopy的前提
      • 需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
    @protocol NSMutableCopying
    - (id)mutableCopyWithZone:(NSZone *)zone;
    @end
    

    2.深复制和浅复制

    • 浅复制(浅拷贝,指针拷贝,shallow copy)
      • 源对象和副本对象是同一个对象
      • 源对象(副本对象)引用计数器+1,相当于做一次retain操作
      • 本质是:没有产生新的对象
        NSString *srcStr = @"gx";
        NSString *copyStr = [srcStr copy];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
    
    • 深复制(深拷贝,内容拷贝,deep copy)
      • 源对象和副本对象是不同的两个对象
      • 源对象引用计数器不变,副本对象计数器为1(因为是新产生的)
      • 本质是:产生了新的对象
        NSString *srcStr = @"gx";
        NSMutableString *copyStr = [srcStr mutableCopy];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
        [copyStr appendString:@" cool"];
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"gx"];
        NSString *copyStr = [srcStr copy];
        [srcStr appendString:@" cool"];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"gx"];
        NSMutableString *copyStr = [srcStr mutableCopy];
        [srcStr appendString:@" cool"];
        [copyStr appendString:@" 520it"];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
    
    copy.png
    • 完全深拷贝:在拷贝的时候,被拷贝对象的每一层都进行了拷贝。

    copy与内存管理


    1.copy与内存管理

    • 浅拷贝

      • 原对象引用计数器+1

      • 必须对原对象进行释放

        char *cstr = "this is a c string";
        NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
        NSLog(@"str = %lu", [str1 retainCount]);
        NSString *str2 = [str1 copy];
        NSLog(@"str = %lu", [str1 retainCount]);
        [str2 release];//必须做一次release
        
    • 深拷贝

      • 必须释放新对象

        char *cstr = "this is a c string";
        NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
        NSLog(@"str = %lu", [str1 retainCount]);
        NSMutableString *str2 = [str1 mutableCopy];
        NSLog(@"str = %lu", [str1 retainCount]);
        [str2 release]; // 必须做一次release
        

    @property中的copy关键字


    1.@property中的copy的作用

    • 防止外界修改内部的值
        @interface Person : NSObject
        @property (nonatomic, retain) NSString *name;
        @end
        NSMutableString *str = [NSMutableString stringWithFormat:@"gx"];
    
        Person *p = [[Person alloc] init];
        p.name = str;
        // person中的属性会被修改
        [str appendString:@" cool"];
        NSLog(@"name = %@", p.name);
    
    • 防止访问对象对象已经释放

      • 不用copy情况

        Person *p = [[Person alloc] init];
        p.name = @"gx";
        Dog *d = [[Dog alloc] init];
        d.age = 10;
        NSLog(@"retainCount = %lu", [d retainCount]); // 1
        p.pBlock = ^{
          // 报错, 调用之前就销毁了
          NSLog(@"age = %d", d.age);
        };
        [d release]; // 0
        p.pBlock();
        [p release];
        
      • 用copy情况

            Person *p = [[Person alloc] init];
            p.name = @"gx";
            Dog *d = [[Dog alloc] init];
            d.age = 10;
            NSLog(@"retainCount = %lu", [d retainCount]); // 1
            p.pBlock = ^{
                // 会对使用到的外界对象进行一次retain
                NSLog(@"age = %d", d.age);
                NSLog(@"retainCount = %lu", [d retainCount]); // 1
            };
            [d release]; // 1
            p.pBlock();
            [p release];
        

    2.@property内存管理策略选择

    • 非ARC
      • 1> copy : 只用于NSString\block
      • 2> retain : 除NSString\block以外的OC对象
      • 3> assign :基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign
    • ARC
      • 1> copy : 只用于NSString\block
      • 2> strong : 除NSString\block以外的OC对象
      • 3> weak : 当2个对象相互引用,一端用strong,一端用weak
      • 4> assgin : 基本数据类型、枚举、结构体(非OC对象)

    自定义的类实现copy操作


    1.自定义类实现copy操作

    • 让类遵守NSCopying协议

    • 实现 copyWithZone:方法,在该方法中返回一个对象的副本即可。

    • 在copyWithZone方法中,创建一个新的对象,并设置该对象的数据与现有对象一致, 并返回该对象.

      zone: 表示空间,分配对象是需要内存空间的,如果指定了zone,就可以指定 新建对象对应的内存空间。但是:zone是一个非常古老的技术,为了避免在堆中出现内存碎片而使用的。在今天的开发中,zone几乎可以忽略

    • 无父类实现

    -(id)copyWithZone(NSZone *)zone{
    
       CustomMode *custom = [[[self class]  copyWithZone:zone]  init];
    
       Custom ->_a = [_a copyWithZone:zone];
    
       Custom -> _c = _c;//不是对象的 直接赋值
    
       Return custom;
    
    }
    
    • 有父类实现

      • 不调用父类方法, 无法拷贝父类中继承的属性
    • 不重写父类copyWithZone, 无法拷贝本来中的特有属性

    -(id)copyWithZone(NSZone *)zone{
    
    CustomModel *custom = [super copyWithZone:zone];
    ….//添加子类属性
    Return custom;
    }
    

    单例设计模式


    1.单例模式概念

    • 什么是单例模式:(Singleton)
      • 单例模式的意图是是的类的对象成为系统中唯一的实例,􏰀供一个访问点,供客户类 共享资源。
    • 什么情况下使用单例?
      • 1、类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方 法。
      • 2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。
    • 单例设计模式的要点:
        1. 某个类只能有一个实例
      • 2)他必须自行创建这个对象
      • 3)必须自行向整个系统􏰀供这个实例;
      • 4)为了保证实例的唯一性,我们必须将
      • 5)这个方法必须是一个静态类

    2.简单的单例模式实现

    #define interfaceSingleton(name)  +(instancetype)share##name
    
    
    #if __has_feature(objc_arc)
    // ARC
    #define implementationSingleton(name)  \
    + (instancetype)share##name \
    { \
    name *instance = [[self alloc] init]; \
    return instance; \
    } \
    static name *_instance = nil; \
    + (instancetype)allocWithZone:(struct _NSZone *)zone \
    { \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
    _instance = [[super allocWithZone:zone] init]; \
    }); \
    return _instance; \
    } \
    - (id)copyWithZone:(NSZone *)zone{ \
    return _instance; \
    } \
    - (id)mutableCopyWithZone:(NSZone *)zone \
    { \
    return _instance; \
    }
    #else
    // MRC
    
    #define implementationSingleton(name)  \
    + (instancetype)share##name \
    { \
    name *instance = [[self alloc] init]; \
    return instance; \
    } \
    static name *_instance = nil; \
    + (instancetype)allocWithZone:(struct _NSZone *)zone \
    { \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
    _instance = [[super allocWithZone:zone] init]; \
    }); \
    return _instance; \
    } \
    - (id)copyWithZone:(NSZone *)zone{ \
    return _instance; \
    } \
    - (id)mutableCopyWithZone:(NSZone *)zone \
    { \
    return _instance; \
    } \
    - (oneway void)release \
    { \
    } \
    - (instancetype)retain \
    { \
    return _instance; \
    } \
    - (NSUInteger)retainCount \
    { \
    return  MAXFLOAT; \
    }
    #endif
    

    相关文章

      网友评论

        本文标题:iOS开发--拷贝及单例模式

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