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

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);
iOS开发--拷贝及单例模式_第1张图片
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开发--拷贝及单例模式)