黑马程序员-IOS-OC基础-浅析Copy语法

本文详细解析了Objective-C中的拷贝机制,包括浅拷贝与深拷贝的区别及应用场景,特别关注了NSString和自定义类的拷贝行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在OC语法中,提供了Copy语法(Copy + MutableCopy)用于对象的拷贝。其中很容易混淆的是浅拷贝和深拷贝。

所谓浅拷贝,即是地址拷贝,并不产生新的对象,而是对原对象的引用计数值加1。而深拷贝,即是对象拷贝,产生新的对象副本,计数器为1。

下面通过一个例子来分析一下这个比较容易乱的Copy:

一、对于NSString/NSMutableString; NSArray/NSMutableArray... 这OC提供的类对象:

以NSString/NSMutableString为例:

对于copy,返回的一定是不可变类型;而mutableCopy,返回的一定是可变类型。

①对于 mutableCopy ,一定是深拷贝。


如果是 NSString ---> NSString;则是浅拷贝;如果是 NSMutableString ---> NSString;则是 深拷贝

如果是 NSString 、NSMutableString ---> NSMutableString;则是深拷贝

注:只有一种情况下是发生浅拷贝:不可变对象 复制到 不可变对象。

?
1
2
3
4
5
6
7
8
9
10
11
//浅拷贝:指针拷贝 不会产生新的对象,源对象计数器加1
void strCopy(){
     
     NSString *str=[[NSString alloc]initWithFormat:@ "abcd" ];
     //因为NSString对象本身就不可变,所以并没产生新的对象,而是返回对象本身,会做一次retain操作,所以源对象也会retain
     NSString *str2=[str copy];
         
     //输出二者的地址,二者的地址是相同的
     NSLog(@ "str --> %p" ,str);
     NSLog(@ "str2 --> %p" ,str2);
}

除了以上这种情形外,其他都是深拷贝。

例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
//深拷贝
void mutableStrCopy(){
     
     NSMutableString *str=[[NSMutableString alloc]initWithFormat:@ "abcd" ];
     
     //会产生一个新的对象计数器1
     NSString *str2=[str copy];
     
     //输出二者的地址,二者的地址是不同的
     NSLog(@ "str --> %p" ,str);
     NSLog(@ "str2 --> %p" ,str2);
}

二、对于自定义对象的Copy: 该类必须实现NSCopying协议,重写 copyWithZone 方法。

同理,对于自定义对象的mutableCopy:必须实现 NSMutableCopying 协议,重写 mutableCopyWithZone 方法。

在NSCopying协议中,其实只有一个协议方法:

?
1
2
3
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end


在NSMutableCopying协议:

?
1
2
3
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end

下面给出一个例子:

?
1
2
3
4
5
6
7
8
9
10
# import <foundation foundation.h= "" >
 
@interface Person : NSObject<nscopying>
 
@property (nonatomic,assign) int age;
@property (nonatomic,copy)NSString *name;
 
-(instancetype)initWithAge:( int )age withName:(NSString*)name;
 
@end </nscopying></foundation>

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# import "Person.h"
 
@implementation Person
 
-(instancetype)initWithAge:( int )age withName:(NSString*)name{
     self = [ super init];
     if (self) {
         self.age = age;
         self.name = name;
     }
     return self;
}
 
-(id)copyWithZone:(NSZone *)zone{
     Person* person = [[[self class ] allocWithZone:zone] initWithAge:self.age withName:self.name];
     return person;
}
 
@end

?
1
2
3
4
5
6
7
8
9
10
11
12
13
int main( int argc, const char * argv[])
{
     @autoreleasepool {
         
         Person *p1 = [[Person alloc] initWithAge: 20 withName:@ "Jack" ];
         Person *p2 = [p1 copy];
         
         //输出两个 Person 对象的地址,二者是不同的
         NSLog(@ "p1 --> %p" ,p1);
         NSLog(@ "p2 --> %p" ,p2);
     }
     return 0 ;
}

加入对于某些自定义对象是不可变的,那么如何办呢?
?
1
2
3
-(id)copyWithZone:(NSZone *)zone{
     return self;
}
这样,输出的两个对象的地址就是相同的了。


下面了解一下关于如果某一个自定义类继承了 这个Person类的情况。

如果某一个子类继承了实现了NSCopying协议的基类,那么该子类也是会自动继承这个协议的方法。但是需要自己重新实现。

例如:有一个Student子类继承了这个Person类:

?
1
2
3
4
5
6
7
8
9
# import <foundation foundation.h= "" >
# import "Person.h"
@interface Student : Person
 
@property (nonatomic,copy)NSString *school;
 
-(instancetype)initWithAge:( int )age withName:(NSString *)name WithSchool:(NSString*)school;
 
@end </foundation>


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# import "Student.h"
 
@implementation Student
 
-(instancetype)initWithAge:( int )age withName:(NSString *)name WithSchool:(NSString*)school{
     self = [ super initWithAge:age withName:name];
     if (self) {
         self.school = school;
     }
     return self;
}
 
-(id)copyWithZone:(NSZone *)zone{
     Student *student = [ super copyWithZone:zone];
     student.school = self.school;
     return student;
}
 
@end

注意其中copyWithZone方法的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值