iOS开发中的NSCopying协议

目录

前言

一、简介

二、实现 NSCopying 的步骤

三、深拷贝与浅拷贝

四、NSCopying类的使用场景

1.防止对象被篡改

2.多线程编程

3.保持对象的状态


前言

        这篇文章主要是讲NSCopying的用法。

一、简介

        在 Objective-C 中,NSCopying协议用于创建对象的副本。这对于需要复制对象而不是简单地引用它们的情况非常有用。实现NSCopying`协议的类必须提供一个方法,用于返回对象的副本。

        我们可以看一下NSCopying的定义:

/***************	Basic protocols		***************/

@protocol NSCopying

- (id)copyWithZone:(nullable NSZone *)zone;

@end

        官方的介绍也很简单,NSCopying是一个基础的协议,这个协议只有一个copyWithZone方法。

        此方法用于创建并返回接收者的副本。zone参数允许指定新对象的内存区域,但通常可以忽略此参数,直接传递 `nil`。

二、实现 NSCopying 的步骤

        实现NSCopying需要两个步骤:

  1. 声明 NSCopying 协议:在头文件中声明类遵守 NSCopying`协议。
  2. 实现 copyWithZone 方法:在实现文件中编写 copyWithZone方法,创建并返回对象的副本。

        以下是一个实现 `NSCopying` 协议的示例:

@interface MyObject : NSObject<NSCopying>

@property (nonatomic,strong) NSString * name;
@property (nonatomic,assign) NSUInteger age;

@end

@implementation MyObject


- (id)copyWithZone:(NSZone *)zone {
    MyObject *copy = [[[self class] allocWithZone:zone] init];
    if (copy) {
        copy->_name = [_name copyWithZone:zone];
        copy->_age = _age;
    }
    return copy;
}

@end

        使用NSCopying的实例代码如下:

    MyObject *original = [[MyObject alloc] init];
    original.name = @"Original";
    original.age = 30;

    MyObject *copy = [original copy];
    NSLog(@"原始对象: %@, Age: %ld", original.name, (long)original.age);
    NSLog(@"深拷贝对象: %@, Age: %ld", copy.name, (long)copy.age);

三、深拷贝与浅拷贝

        浅拷贝:新对象的属性指向原对象的同一实例。通常通过直接赋值实现。
        深拷贝:新对象的属性是原对象属性的副本。需要递归复制每个属性。

        在上面的示例中,name 属性是通过copyWithZone:方法进行深拷贝,而 age属性则是简单的浅拷贝。

        使用 NSCopying 的注意事项

1. 不可变对象:对于不可变对象,浅拷贝和深拷贝通常没有区别。
2. 可变对象:对于可变对象,必须深拷贝以确保新对象的独立性。
3. 自定义类:实现NSCopying协议时,需要确保所有属性都正确复制。

四、NSCopying类的使用场景

1.防止对象被篡改

        还以上面的MyObject对象为例,假如我们的MyObject只有两个属性name和age两个属性,当我们进行赋值操作之后,修改新对象的值之后,可能会修改原来的想的值。

#import "ViewController.h"

@interface MyObject : NSObject

@property (nonatomic,strong) NSString * name;
@property (nonatomic,assign) NSUInteger age;

@end

@implementation MyObject

@end



@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    MyObject *original = [[MyObject alloc] init];
    original.name = @"Original";
    original.age = 30;

    MyObject *copy =original;
    //修改对象的属性
    copy.name = @"Modified";
    copy.age = 20;
    NSLog(@"原始对象: %@, Age: %ld", original.name, (long)original.age);
    NSLog(@"新对象: %@, Age: %ld", copy.name, (long)copy.age);
    
}


@end

        上述代码运行之后, 控制台打印信息如下:

        在上述的代码中,我们修改copy对象的name和age之后,原始对象的属性也被修改。

        当我们的MyObject对象实现了NSCopying协议之后,对象的拷贝就变成了深拷贝,这个时候再次修改对象的值可以防止原来对象的值被修改。

        代码如下:

#import "ViewController.h"

@interface MyObject : NSObject

@property (nonatomic,strong) NSString * name;
@property (nonatomic,assign) NSUInteger age;

@end

@implementation MyObject


- (id)copyWithZone:(NSZone *)zone {
    MyObject *copy = [[[self class] allocWithZone:zone] init];
    if (copy) {
        copy->_name = [_name copyWithZone:zone];
        copy->_age = _age;
    }
    return copy;
}

@end



@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    MyObject *original = [[MyObject alloc] init];
    original.name = @"Original";
    original.age = 30;

    MyObject *copy = [original copy];
    //修改对象的属性
    copy.name = @"Modified";
    copy.age = 20;
    NSLog(@"原始对象: %@, Age: %ld", original.name, (long)original.age);
    NSLog(@"深拷贝对象: %@, Age: %ld", copy.name, (long)copy.age);
}


@end

        代码运行之后,控制台打印信息如下:

        我们发现即使我们修改了copy对象的name属性,也不会影响原来的对象的值被修改。

2.多线程编程

- (void)method2{
    //MyObject实现了NSCopying协议
    dispatch_queue_t queue = dispatch_queue_create("com.example.myqueue", DISPATCH_QUEUE_CONCURRENT);
    MyObject *sharedObject = [[MyObject alloc] init];
    sharedObject.name = @"Shared";
    //在每个线程中使用拷贝的对象,保证线程的安全
    dispatch_async(queue, ^{
        MyObject *threadCopy = [sharedObject copy];
        threadCopy.name = @"线程1";
        NSLog(@"线程1: %@", threadCopy.name);
    });

    dispatch_async(queue, ^{
        MyObject *threadCopy = [sharedObject copy];
        threadCopy.name = @"线程2";
        NSLog(@"线程2: %@", threadCopy.name);
    });
}

3.保持对象的状态

        假如我们正在修改一个对象的时候,发生了异常情况需要恢复到修改之前的状态,我们就可以通过下面的代码实现。

- (void)keepThreadState{
    // 假设MyObject实现了 NSCopying
    MyObject *original = [[MyObject alloc] init];
    original.name = @"Original";
    original.age = 30;

    // 修改之前保存对象的状态
    MyObject *savedState = [original copy];
    original.name = @"Modified";
    NSLog(@"修改: %@", original.name); // Output: Modified
    // 必要的时候恢复savedState
    original = savedState;
    NSLog(@"恢复: %@", original.name); // Output: Original
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫柱子哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值