文章目录
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是不可修改的数据了