自定义类实现mutableCopy(Runtime方式动态添加属性)

前言

需求是自定义的一个类需要实现mutableCopy。这样操作就保证数据一样的前提下,修改这个类就不会相互影响了。

一、要实现mutableCopy的前提

**注意!**要实现mutableCopy的话这个类需要遵守NSMutableCopying 协议,不遵守直接调用 [类名 mutableCopy]的话会造成下方提示的方法未找到的崩溃。

[Message mutableCopyWithZone:]: unrecognized selector sent to instance 0x282326340

所有我们就需要遵守以下协议

@interface Message : NSObject <NSMutableCopying>

二、实现代码

话不多少上代码 ✧(≖ ◡ ≖), 在.m中实现下面的方法。
注:Message是我自己创建的类,如果他是其他类麻烦请自行进行替换就行了。

- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    
    Message * objCopy = [[Message alloc] init];
    unsigned int count;
    //得到这个类的属性数量以及这个类声明的属性
    objc_property_t * properties = class_copyPropertyList(object_getClass(objCopy), &count);
    NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
    //遍历属性名称并添加到数组中
    for (unsigned int i = 0; i < count; i++) {
        const char* propertyName = property_getName(properties[i]);
        [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }
    //释放 objc_property_t
    free(properties);
    
    //使用KVC赋值
    for (int i = 0; i < count ; i++)
    {
        NSString *name=[propertyArray objectAtIndex:i];
        id value=[self valueForKey:name];
        if([value respondsToSelector:@selector(mutableCopyWithZone:)]){
            [objCopy setValue:[value mutableCopy] forKey:name];
        }
        else{
            
        }
    }
    return objCopy;
}

三、分析代码

1	Message * objCopy = [[Message alloc] init];
2	unsigned int count;

这两行我就不进行解释了

3	objc_property_t * properties = class_copyPropertyList(object_getClass(objCopy), &count);

这第三行他到底做了什么呢?于是我去苹果官方开放的源码中去找,找到objc-runtime-new.mm这个文件。有人会不会问为啥objc-runtime-new 而不是objc-runtime-old呢?objc-runtime-old 是老的啦,被抛弃的╮(╯▽╰)╭。所以这里就不看old文件了,直接看new文件。
于是在文件中就可以发现这段代码

objc_property_t *
class_copyPropertyList(Class cls, unsigned int *outCount)
{
    if (!cls) {
        if (outCount) *outCount = 0;
        return nil;
    }

    mutex_locker_t lock(runtimeLock);

    checkIsKnownClass(cls);
    assert(cls->isRealized());
    
    auto rw = cls->data();

    property_t **result = nil;
    unsigned int count = rw->properties.count();
    if (count > 0) {
        result = (property_t **)malloc((count + 1) * sizeof(property_t *));

        count = 0;
        for (auto& prop : rw->properties) {
            result[count++] = &prop;
        }
        result[count] = nil;
    }

    if (outCount) *outCount = count;
    return (objc_property_t *)result;
}

原来是用来获取这个类的属性数量以及这个类声明的属性。会返回一个objc_property_t 的结构体。
count 就是属性数量
result 里面就描述了类声明的属性。

咱们顺便看看 objc_property_t 这个结构体里面有哪些东东

struct property_t {
    const char *name;
    const char *attributes;
};

一个name和attributes…

接着我们看

4	NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];
 
5    for (unsigned int i = 0; i < count; i++) {
6        const char* propertyName = property_getName(properties[i]);
7        [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];
    }

我们可以根据class_copyPropertyList这个方法获取到的数量来做一个循环

const char *property_getName(objc_property_t prop)
{
    return prop->name;
}

property_getName 其实就是获取了 objc_property_t 这个结构体当中的name。不过注意这个name 是char 类型的,我们需要转换一下,转成NSString,方面我们使用。所以就需要下面这个方法啦

[propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]];

接下来是很重要的第九行

9	free(properties);

这一行properties必须释放,否则会造成内存泄露等,苹果官方注释也提到这么一句话:
Caller must free the block.

后面几行我就不看了,就是利用KVC进行赋值。

至此就分析结束了。

四、结束语

本人也在不断的学习以及摸索中,如有不对的地方欢迎指出,在下方回复或者邮件都可以,再此感谢大家的阅读。

邮箱:zzx986661689@gmail.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值