OC语言 - 内存管理:copy | 深拷贝 | 浅拷贝 | 自定义拷贝
copy 实现原理
1 - copy 修饰属性时,其 setter/getter 方法内部实现原理同 retain 类似
// - Person.h
#import <Foundation/Foundation.h> @interface Person : NSObject @property(nonatomic,copy)NSString *name; @end
// - Person.m
1 #import "Person.h" 2 @implementation Person 3 4 -(void)dealloc{ 5 6 [_name release]; 7 NSLog(@"%@ 销毁",self); 8 [super dealloc]; 9 } 10 11 12 -(void)setName:(NSString *)name{ 13 14 if (_name != name) { 15 [_name release]; 16 _name = [name copy];// 不同点:使用的是 copy 17 } 18 } 19 20 -(NSString *)getName{ 21 22 return [[_name retain] autorelease]; 23 } 24 25 @end
深拷贝 | 浅拷贝
1 - 对不可变 NSString、NSArray、NSDictionary 等进行 copy 属浅拷贝。它拷贝指针,并没有拷贝出新对象,copy 相当于是 retain
NSString *str01 = [NSString stringWithFormat:@"小白菜"]; NSLog(@"%lu %p",[str01 retainCount],str01);// 1 0x100502850 NSString *newStr01 = [str01 copy]; NSLog(@"%lu %p",[newStr01 retainCount],newStr01);// 2 0x100502850
2 - 对可变 NSMutableString、NSMutableArray、NSMutableDictionary 等进行 copy 是深拷贝。它会拷贝出一个新对象且新对象是不可变的
NSMutableString *str02 = [NSMutableString stringWithFormat:@"科技"]; NSLog(@"%lu %p",[str02 retainCount],str02); // 1 0x103306120 NSString *newStr02 = [str02 copy];// 返回不可变 NSLog(@"%lu %@ %p",[newStr02 retainCount],newStr02,newStr02);// 1 科技 0x103104230
3 - 对 NSString/NSMutableString、NSArray/NSMutableArray、NSDictionary/NSMutableDictionary 进行 mutableCopy 是深拷贝。它会拷贝出一个新对象且新对象是可变的
1 NSString *str03 = [NSString stringWithFormat:@"小二黑结婚"]; 2 NSMutableString *newSt03 = [str03 mutableCopy];// 返回可变字符串 3 NSLog(@"%p %p",str03,newSt03);// 0x100508460 0x1005067c0 4 5 NSMutableString *str04 = [NSMutableString stringWithFormat:@"平凡的世界"]; 6 NSMutableString *newStr04 = [str04 mutableCopy];
自定义拷贝
1 - 对类进行拷贝:当一个类需要 copy 时要接受 NSCopying 协议,并且实现协议中的 copyWithZone 方法
// - Student.h
#import <Foundation/Foundation.h> @interface Student : NSObject<NSCopying> // 协议 @property (nonatomic,copy)NSString *name; @property (nonatomic,copy)NSString *sex; @property (nonatomic,assign)NSInteger age; - (id)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger )age; - (void)sayHI; @end
// - Student.m
1 #import "Student.h" 2 @implementation Student 3 4 -(void)dealloc{ 5 6 self.name = nil; 7 self.sex = nil; 8 [super dealloc]; 9 } 10 11 - (void)sayHI{ 12 NSLog(@"I am a student,name : %@,sex : %@,age : %ld",_name,_sex,_age); 13 } 14 15 - (id)initWithName:(NSString *)name sex:(NSString *)sex age:(NSInteger )age{ 16 self = [super init]; 17 18 if (self) { 19 _name = name; 20 _sex = sex; 21 _age = age; 22 } 23 return self; 24 } 25 26 // 当一个对象 copy 时会自动调用到 copyWithZone: 方法 27 // NSZone 是用于记录原对象的内存结构信息 28 -(id)copyWithZone:(NSZone *)zone{ 29 30 // 如何实现协议中的方法 31 // 根据原对象的内存结构信息创建一个新对象 32 // 把原对象实例变量的内容复制给新对象 33 Student *newStudent = [Student allocWithZone:zone]; 34 newStudent.name = self.name; 35 newStudent.sex = self.sex; 36 newStudent.age = self.age; 37 38 return newStudent; 39 } 40 41 @end
// - main.m
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 4 int main(int argc, const char * argv[]) { 5 6 Student *stu01 = [[Student alloc] initWithName:@"Bruce" sex:@"male" age:17]; 7 NSLog(@"%@===%@ %@ %ld",stu01,stu01.name,stu01.sex,stu01.age);// <Student: 0x101dafb80>===Bruce male 17 8 NSLog(@"%lu",[stu01 retainCount]);// 1 9 10 // copy 会拷贝出一份新的对象 11 Student *newstudent = [stu01 copy]; 12 // newstudent 和 stu01 地址不一样 13 NSLog(@"%@===%@ %@ %ld",newstudent,newstudent.name,newstudent.sex,newstudent.age);// <Student: 0x104904320> Bruce male 17 14 NSLog(@"stu04---%lu newstudent---%lu ",[stu01 retainCount],[newstudent retainCount]);// stu01---1 newstudent---1 15 16 Student *newstudentII = [newstudent copy]; 17 NSLog(@"newstudent---%lu newstudentII---%lu ",[newstudent retainCount],[newstudentII retainCount]);// newstudent---1 newstudentII---1 18 19 return 0; 20 }
小结
1 - copy 修饰的属性仅限于 NSString、NSArray、NSDictionary,也是苹果推荐的使用方式
2 - 对于 NSMutableArray、NSMutableString、NSMutableDictionary 等可变因素一旦 copy 后就会生成一个不可变的对象,这在实际开发中是我们不想看到的
// - Person.h
#import <Foundation/Foundation.h> @interface Person : NSObject @property(copy,nonatomic)NSMutableArray *mutArray; @end
// - main.m
1 #import <Foundation/Foundation.h> 2 #import "Person.h" 3 int main(int argc, const char * argv[]) { 4 5 Person *p = [Person new]; 6 7 NSMutableArray *array01 = [NSMutableArray arrayWithCapacity:1]; 8 p.mutArray = array01; 9 [p.mutArray addObject:@"5"];// crash 10 11 // 因为属性 mutArray 是 copy 修饰的 12 // 经过点语法赋值之后 p.mutArray 拿到的是新拷贝出的不可变数组 13 // 不可变数组调用了一个并不存在的方法 addObject,故 crash 14 15 return 0; 16 17 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)