iOS开发系列--基于MJExtension的Runtime简单使用

jscjxysx 2019-06-28

首先了解两个概念:深拷贝和浅拷贝
简单来说,深拷贝就是内容拷贝,浅拷贝就是指针拷贝。更具体的用法,就不作过多解释,自行百度吧。

// 字符串是直接赋值的,右侧如果是copy,那么就是浅拷贝;右侧如果是mutableCopy,那么就是深拷贝。  
   NSString *string1 = @"helloworld";  
   NSString *string2 = [string1 copy]; // 浅拷贝  
   NSString *string3 = [string1 mutableCopy]; // 深拷贝  
   NSMutableString *string4 = [string1 copy]; // 浅拷贝  
   NSMutableString *string5 = [string1 mutableCopy]; // 深拷贝  
  
   NSLog(@"string1 = %d;string2 = %d",string1,string2);  
   NSLog(@"string1 = %d;string3 = %d",string1,string3);  
   NSLog(@"string1 = %d;string4 = %d",string1,string4);  
   NSLog(@"string1 = %d;string5 = %d",string1,string5);

打印结果:

iOS开发系列--基于MJExtension的Runtime简单使用

使用场景:

在某些时候,需要复制一份相同的Model数据,但是又不影响原Model,类似上述的深拷贝,又或者在大量相同字段中需要改变其中一个字段的值。由于Model数据的复杂性或者没有实现NSCopy协议,简单的使用Copy来拷贝可能无法达到预期效果,由此就有了MJExtension的衍生使用。

核心代码:

//
//  NSObject+TMCopy.h
//  LJDY
//
//  Created by TIM on 16/8/23.
//  Copyright © 2016年 mimi. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSObject (TMCopy)

/**
 实现类的copy
 */
- (id)tm_copy;

@end
//
//  NSObject+TMCopy.m
//  LJDY
//
//  Created by TIM on 16/8/23.
//  Copyright © 2016年 mimi. All rights reserved.
//

#import "NSObject+TMCopy.h"

@implementation NSObject (TMCopy)

- (id)tm_copy
{
    Class clazz = [self class];;
    __strong Class newClass = [[clazz alloc] init];
    Class superClass = self.superclass;
    while (superClass && ![NSStringFromClass(superClass) isEqualToString:@"NSObject"]) {
        [self setupValueWithNewClass:newClass Class:superClass];
        superClass = superClass.superclass;
    }
    [self setupValueWithNewClass:newClass Class:clazz];
    return newClass;
}

- (void)setupValueWithNewClass:(Class)newClass
                         Class:(Class)clazz
{
    int i;
    unsigned int propertyCount = 0;
    //runtime 获取类的所有属性
    objc_property_t *propertyList = class_copyPropertyList(clazz, &propertyCount);
    NSDictionary *dic;
    //获取数组中需要转换的模型类
    if ([clazz respondsToSelector:@selector(mj_objectClassInArray)]) {
        dic = [clazz mj_objectClassInArray];
    }
    for (i = 0; i < propertyCount; i++) {
        objc_property_t *thisProperty = propertyList + i;
        const char *propertyName = property_getName(*thisProperty);
        //属性名
        NSString *property = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
        id value = [self valueForKey:property];
        //如果对象是模型类,则再次遍历模型类中的属性
        if (dic && [[dic allKeys] containsObject:property]) {
            //特殊处理模型中包含模型数组
            if ([value isKindOfClass:[NSArray class]]) {
                NSMutableArray *modelArray = [NSMutableArray array];
                for (Class _arrayClass in value) {
                    [modelArray addObject:[_arrayClass tm_copy]];
                }
                [newClass setValue:modelArray forKey:property];
            }
            else {
                id _class = [value tm_copy];
                [newClass setValue:_class forKey:property];
            }
        }
        else {
            [newClass setValue:value forKey:property];
        }
    }
    free(propertyList);
}

@end

使用方法:

FriendItem *_item = [item tm_copy];

结果:

iOS开发系列--基于MJExtension的Runtime简单使用

相关推荐

定格 / 0评论 2019-12-11