当前位置:网站首页>[OC-Foundation框架]--<Copy对象复制>

[OC-Foundation框架]--<Copy对象复制>

2022-07-06 08:50:00 关于小司

copy 与 mutableCopy 方法

copy方法

copy 方法用于复制对象的副本,copy方法总返回对象的不可修改副本,即使该对象本身是可修改的

  • 例如 :NSMutableString 的copy方法 返回不可修改的字符串对象

mutableCopy 方法

  • mutableCopy 方法用于复制对象的可变副本,通常来说,mutableCopy 方法返回该对象可修改的副本,即使被复制的的对象是不可修改的

mutableCopy 方法 copy方法的共同特点

无论如何 copy 和 mutableCopy 返回的总是对象的副本,当程序对复制的副本进行修改时,原对象通常不会受到影响

mutableCopy和copy 程序实例

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
    
        NSMutableString *book = [NSMutableString stringWithString:@"疯狂iOS勒布朗"];
        NSMutableString *bookCopy = [book mutableCopy];
        [bookCopy replaceCharactersInRange:
            NSMakeRange (2, 3)
            withString:@"Android"];
        NSLog(@"book 的值:%@", book);
        // 字符串副本发生了改变
        NSLog(@" bookCopy的值 为 %@", bookCopy);


        NSString *str = @"fkiOS";
        // 赋值str(不可变子串的副本 --可变)
        NSMutableString * strCopy = [str mutableCopy];
        //向可变后追加字符
        [strCopy appendString:@" ,org"];
        NSLog(@"%@ ", strCopy);


        //调用book的Copy方法返回一个不可修改副本·
        NSMutableString* bookCopy2 = [book copy];
        // 不可修改发生错误
        //Thread 1: "Attempt to mutate immutable object with appendString:"
        //注释
// [bookCopy2 appendString:@"123456"];

    }
    return 0;
}`在这里插入代码片`
  • 调用一个方法返回一个不可修改的副本时候
 //调用book的Copy方法返回一个不可修改副本·
        NSMutableString* bookCopy2 = [book copy];
        // 不可修改发生错误
        //Thread 1: "Attempt to mutate immutable object with appendString:"
        //注释
// [bookCopy2 appendString:@"123456"];

  • 在上面的程序中,虽然str是不可变字符串 但是通过mutableCopy 方法依然得到依然是可变副本,因此可以对strCopy进行修改
  • 虽然book是可变字符串但是调用了copy的发哦的事不可变副本 因此对bookCopy2字符串进行修改 会导致错误

NScopying 与 NSmutableCopying 协议

通过copy 与 mutableCopy 方法复制对象的副本开起来很方便
但是自定义类是否可代用copy 与 mutableCopy 方法来复制副本吗?

OC规定

  • Xcode的 报错可以看出 虽然NSObject提供了copy和 mutablecopy方法 但自定义类并不能调用这两个方法来复制自身

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

此细节不过多赘述

深复制和浅复制

浅复制

我们来看一个简单的对于类复制的例子
定义一个FKdog对象

注意在接口部分声明协议NSCopying

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FKdog : NSObject  <NSCopying> //声明copy协议 因为是一个类
@property (nonatomic, strong) NSMutableString* name;
@property (nonatomic, assign) int age;
@end

NS_ASSUME_NONNULL_END

浅复制的实现部分

- (id)copyWithZone:(nullable NSZone *)zone {
    
    FKdog* dog = [[[self class] allocWithZone:zone] init];
    dog.name = self.name; //注意区别
    dog.age = self.age;
    return dog;
}
#import <Foundation/Foundation.h>
#import "FKdog.h"

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
    
        FKdog *d1 = [[FKdog alloc] init];
        d1.name = [NSMutableString stringWithString:@"旺财"];
        d1.age = 20;
        FKdog *d2 = [d1 copy];
        [d2.name replaceCharactersInRange:NSMakeRange(0, 2) withString:@"旺财2号"];
        NSLog(@"%@, %d", d1.name, d1.age);
        NSLog(@"%@, %d", d2.name, d2.age);
    }
    return 0;
}

在这里插入图片描述

关于浅复制

上面调用了dog1 的copy方法复制了一个副本,并将副本复制dog2变量,接下来修改了dog2的name属性 输出

  • 发现我们只是修改了dog2的name 但是为何dog1 也变化了

  • 在这里插入图片描述

  • 注意,name是一个指针类型的变量,该变量里存放的字符串的地址,并不是字符串本身,这样赋值的效果是dog的name 属性与被复制对象self的name属性指向同一个字符串 而age变量不困如何改变 dog1都不会变

  • (我们把dog2的年龄改为100 发现dog1 还是20)如下

  • 2022-05-25 19:19:55.815766+0800 OC-copy[15837:2289009] 旺财2号, 20 2022-05-25 19:19:55.815971+0800 OC-copy[15837:2289009] 旺财2号, 100 Program ended with exit code: 0

  • 我们可以得出结论 只要是浅复制 只要是指针类型的属性

  • 改变任意一个都会改变另一个 的属性值

  • 在这里插入图片描述

深复制

深复制则会采取与之不同的方式 神复制不仅会复制对象本身,还会递归复制每个指针类型的属性 直到两个对象没有任何的公共部分 将实现NSCopy协议的修改即可实现深复制

浅复制到深复制

#import "FKdog.h"

@implementation FKdog

- (id)copyWithZone:(nullable NSZone *)zone {
    
    FKdog* dog = [[[self class] allocWithZone:zone] init];
    dog.name = [self.name mutableCopy];
    //修改如下在指针类型变量的self之加上
    //mutableCopy
    dog.age = self.age;
    return dog;
}

@end

在这里插入图片描述

  • 可以看到dog1 的指针类型name不改变

关于深复制

  • 上面程序中并没有简单地将被复制对象的 name 属性值赋给新对象的 name 属性,而是先将原对象的 name 属性值复制了一份可变副本,再将该可变副本的值赋给新对象的name 属性。
    这样就保证了原 FKDog 对象与新的 FKDog 对象之问没有任何共用的部分,这就实现了深复制。

  • 当 FKDog 实现了深复制之后,再次编译、运行上面的 程序,将可以看到两个FKDog 对象之问没有任何关联,当一个FKDog对象的name 属性值改变时,另一个 FKDog对象的 name 属性值不会受到任何影响

     Foundation 框架中的类大部分都只实现了浅复制。
    

额外的知识增加了

对于我们的浅复制 协议实现代码

- (id)copyWithZone:(nullable NSZone *)zone {
    
    FKdog* dog = [[[self class] allocWithZone:zone] init];
    dog.name = self.name; //注意区别
    dog.age = self.age;
    return dog;
}

#import <Foundation/Foundation.h>
#import "FKdog.h"

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
    
        FKdog *d1 = [[FKdog alloc] init];
        d1.name = [NSMutableString stringWithString:@"旺财"];
        d1.age = 20;
        FKdog *d2 = [d1 copy];
        [d2.name replaceCharactersInRange:NSMakeRange(0, 2) withString:@"旺财2号"];
        NSLog(@"%@, %d", d1.name, d1.age);
        NSLog(@"%@, %d", d2.name, d2.age);
    }
    return 0;
}

注意我们在给dog2赋值的时候 用的是copy方法但是我们此时的copy并没有变成可变copy 为什么dog2的name还可以被 改变呢?

-因为 我们在写NSCopying协议的时候进行了直等于符号 相当于我们在内部重写了copy方法这样子copy方法就会改变了
如果把方法变成这样子

   dog.name = [self.name copy]; //注意区别

那么系统就会提示 dog2是不可修改的数据了

原网站

版权声明
本文为[关于小司]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_61639290/article/details/124955361