当前位置: 首页>编程语言>正文

iOS 模型数组拷贝以及model的NSCopying的runtime实现。

主要目的是为了记录

问题描述:

通常对于需要实现对模型的拷贝都需要先实现model的 NSCopying,NSMutableCopying协议。但这里存在一个问题:对于包含model(实现copy协议的)的数组使用拷贝操作,只会对数组本身进行拷贝,数组的内的model不会进行copy。

一。实现模型数组深拷贝的方法:

 1.归档解档实现数组内部元素拷贝。
   对model使用 归档的话,model的遵循NSCoding协议且实现协议。

  @interface DataModel : NSObject<NSCoding,NSCopying,NSMutableCopying>
  @property (nonatomic , copy)   NSString           * title;
  @property (nonatomic , copy)   NSString           * subTitle;
  @property (nonatomic , copy)   NSString           * detail;
  @property (nonatomic , copy)   NSString           * icon;
  @property (nonatomic , assign)  float                cellHeigjt;
  @property (nonatomic , strong)  NSArray<SubModel *>*  subModelArray;
  @property (nonatomic , strong)  SubModel           * subModel;
  @end

   @implementation DataModel

    + (NSDictionary *)mj_objectClassInArray
   {
        return @{@"subModelArray":@"SubModel"};
    }
    - (id)initWithCoder: (NSCoder *)coder
     {
        if (self = [super init])
      {
         self.title = [coder decodeObjectForKey:@"title"];
         self.subTitle = [coder decodeObjectForKey:@"subTitle"];
         self.detail = [coder decodeObjectForKey:@"detail"];
         self.icon = [coder decodeObjectForKey:@"icon"];
         self.cellHeigjt = [coder decodeFloatForKey:@"cellHeigjt"];
         self.subModelArray = [coder decodeObjectForKey:@"subModelArray"];
          self.subModel = [coder decodeObjectForKey:@"subModel"];
       }
      return self;
     }

      - (void) encodeWithCoder: (NSCoder *)coder
    {
         [coder encodeObject:self.title forKey:@"title"];
         [coder encodeObject:self.subTitle forKey:@"subTitle"];
         [coder encodeObject:self.detail forKey:@"detail"];
         [coder encodeObject:self.icon forKey:@"icon"];
         [coder encodeFloat:self.cellHeigjt forKey:@"cellHeigjt"];
         [coder encodeObject:self.subModelArray forKey:@"subModelArray"];
        [coder encodeObject:self.subModel forKey:@"subModel"];
    }

NSArray * trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:@[dataModel]]];

所得的数组以及数组内的model都是深copy。

  2.系统方法:(推荐使用)
 - (instancetype)initWithArray:(NSArray<ObjectType> *)array copyItems:(BOOL)flag

NSMutableArray * array = [NSMutableArray arrayWithArray:@[model,model1]];
NSArray *lastArray = [[NSArray alloc]initWithArray:array copyItems:YES];
所得的数组以及数组内的model都是深copy。

二。结合runtime的特性以及模型数组深拷贝的方法,我们可以实现model的多层次数组模型的copy。

  @interface DataModel : NSObject<NSCopying,NSMutableCopying>
  @property (nonatomic , copy)   NSString           * title;
  @property (nonatomic , copy)   NSString           * subTitle;
  @property (nonatomic , copy)   NSString           * detail;
  @property (nonatomic , copy)   NSString           * icon;
  @property (nonatomic , assign)  float                cellHeigjt;
  @property (nonatomic , strong)  NSArray<SubModel *>*  subModelArray;
  @property (nonatomic , strong)  SubModel           * subModel;
  @end

   @implementation DataModel
      //##下面代码你只需要更换下model的类型,可直接复用。(在使用的地方需要导入   #import <objc/message.h>)
     -(id)copyWithZone:(NSZone *)zone{
           id objCopy = [[[self class] allocWithZone:zone] init];
            unsigned int count = 0;
            objc_property_t *properties = class_copyPropertyList([self class], &count);
            for (int i = 0; i<count; i++) {
                 objc_property_t property = properties[i];
                 const char *name = property_getName(property);
                 NSString *propertyName = [NSString stringWithUTF8String:name];
                 id value = [self valueForKey:propertyName];
                 if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
                       id valueCopy  = [[NSArray alloc]initWithArray:value copyItems:YES];
                        [objCopy setValue:valueCopy forKey:propertyName];
                  }else if (value) {
                          [objCopy setValue:[value copy] forKey:propertyName];
                  }
             }
             free(properties);
            return objCopy;
         }

         -(id)mutableCopyWithZone:(NSZone *)zone{
               id objCopy = [[[self class] allocWithZone:zone] init];
              unsigned int count = 0;
              objc_property_t *properties = class_copyPropertyList([self class], &count);
              for (int i = 0; i<count; i++) {
                    objc_property_t property = properties[i];
                    const char *name = property_getName(property);
                     NSString *propertyName = [NSString stringWithUTF8String:name];
                     id value = [self valueForKey:propertyName];
                    if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
                        id valueCopy  = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
                        [objCopy setValue:valueCopy forKey:propertyName];
                     }else if(value){
                           [objCopy setValue:[value copy] forKey:propertyName];
                    }
               }
                     free(properties);
                 return objCopy;
      }
     + (NSDictionary *)mj_objectClassInArray
     {
          return @{@"subModelArray":@"SubModel"};
     }

     @end


      @interface SubModel : NSObject<NSCopying,NSMutableCopying>
      @property (nonatomic , copy) NSString *title;
      @property (nonatomic , copy) NSString *subTitle;
      @property (nonatomic , copy) NSString *text;
      @property (nonatomic , copy) NSString *url;
      @property (nonatomic , assign) float   cellHeigjt;
      @property (nonatomic , strong)  ThridModel *thrid;
      @property (nonatomic , strong)  NSArray<ThridModel*> *thridArray;
      @property (nonatomic , strong)  NSArray<ThridModel*> *thridSubArray;
      @end

      @implementation SubModel

       +(NSDictionary *)mj_objectClassInArray
      {
         return @{@"thridArray":@"ThridModel"};
        }

       -(id)copyWithZone:(NSZone *)zone{
              id objCopy = [[[self class] allocWithZone:zone] init];
              unsigned int count = 0;
              objc_property_t *properties = class_copyPropertyList([self class], &count);
              for (int i = 0; i<count; i++) {
                      objc_property_t property = properties[i];
                      const char *name = property_getName(property);
                      NSString *propertyName = [NSString stringWithUTF8String:name];
                      id value = [self valueForKey:propertyName];
                      if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
                           id valueCopy  = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
                           [objCopy setValue:valueCopy forKey:propertyName];
                       }else if(value){
                           [objCopy setValue:[value copy] forKey:propertyName];
                    }
               }
                     free(properties);
              return objCopy;
         }

        -(id)mutableCopyWithZone:(NSZone *)zone{
               id objCopy = [[[self class] allocWithZone:zone] init];
              unsigned int count = 0;
              objc_property_t *properties = class_copyPropertyList([self class], &count);
              for (int i = 0; i<count; i++) {
                    objc_property_t property = properties[i];
                    const char *name = property_getName(property);
                     NSString *propertyName = [NSString stringWithUTF8String:name];
                     id value = [self valueForKey:propertyName];
                    if (value&&([value isKindOfClass:[NSMutableArray class]]||[value isKindOfClass:[NSArray class]])) {
                        id valueCopy  = [[NSMutableArray alloc]initWithArray:value copyItems:YES];
                        [objCopy setValue:valueCopy forKey:propertyName];
                     }else if(value){
                           [objCopy setValue:[value copy] forKey:propertyName];
                    }
               }
                     free(properties);
                 return objCopy;
      }
     
   @end

     DataModel * dataModel = [DataModel mj_objectWithKeyValues:dict2] ;
     DataModel * copyDataModel = [dataModel  copy];

到此就实现了对model的直接copy,不管model里面是否含有包含其他model的数组。拷贝后,都能得到一个全新的model。


https://www.xamrdz.com/lan/5s72016661.html

相关文章: