Objective-C 深复制和浅复制与<NSCopying>协议

1.简单复制只能实现浅拷贝:指针赋值,使两个指针指向相同的一块内存空间,操作不安全。

2. Foundation类已经遵守了<NSCopying>和 <NSMutableCopying>协议,即实现了copy和mutableCopy方法,因此Foundation对象可以使用这些方法创建对象的副本或可变副本

@protocol NSCopying

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

@end

@protocol NSMutableCopying

- (id)mutableCopyWithZone:(NSZone *)zone;

@end


3.用户自定义类遵守<NSCopying>协议和<NSMutableCopying>协议,则必须实现copyWithZone方法和mutableCopyWithZone方法,否则该类对象无法响应copy和mutableCopy消息 

4.实现copyWithZone方法,例:

       

-(id)copyWithZone:(NSZone *)zone

{

         Student *stu = [[Student allocWithZone:zone]initWithName:self.name Age:self.age];

         return stu;

}

对应main函数中:假设已经有一个Student对象stu1;

则:Student stu2 = [stu1 copy];

实现stu2是stu1的副本,这里是深复制,stu1和stu2分别对应不同内存。

 

5. 如果你的类产生了子类,那么copyWithZone:方法也将

被继承

Student *stu = [[Student allocWithZone: zone] init];

 该方法应该改为: Student *stu = [[[self class] allocWithZone: zone]init];

 如果编写一个类的copyWithZone:方法那么子类的方法应该先调用父类的copy方法以复制继承来的copy实例变量.


1 NSCopying与NSMutableCopying协议

用copy方法能得到字符串的不可变副本,而mutableCopy方法能得到字符串的可变副本。 

但是如果对自定义的类,我们不能直接使用copy和mutableCopy方法,需要让类遵守NSCopying与NSMutableCopying协议,然后实现继承自协议的copyWithZone:方法和mutableCopyWithZone:方法,这两个方法返回的是对象本身,得到一个对象的副本。

总之,为了保证一个自定义的类的对象使用copy方法产生一个不可变的副本,需要做两步: 

1. 让该类继承NSCopying协议。 

2. 在类的代码实现部分重写继承自NSCopying协议的CopyWithZone:方法,该方法返回一个该类的不可变对象副本。

为了保证一个自定义的类的对象使用mutableCopy方法产生一个可变的副本,需要做两步: 

1. 让该类继承NSMutableCopying协议。 

2. 在类的代码实现部分重写继承自NSMutableCopying协议的mutableCopyWithZone:方法,该方法返回一个该类的可变对象副本。

2 深复制和浅复制

代码示例如下: 

GKHUser.h

[code]#import <Foundation/Foundation.h>

//继承NSCopying和NSMutableCopying协议
@interface GKHUser : NSObject <NSCopying, NSMutableCopying>
@property (nonatomic, strong) NSMutableString *name;//类似retain类型,引用计数
@property (nonatomic, assign) int age;
@end


GKHUser.m

[code]#import "GKHUser.h"

@implementation GKHUser

//重写copyWithZone:方法
- (id) copyWithZone:(NSZone *)zone {
    NSLog(@"执行copyWithZone:方法");
    //使用zone参数创建一个GKHUser对象
    GKHUser *user = [[[self class] allocWithZone:zone] init];

    user.name = self.name;//这里只是浅复制
    user.age = self.age;
    return user;
}

//重写mutableCopyWithZone:方法
- (id) mutableCopyWithZone:(NSZone *)zone {
    NSLog(@"执行mutableCopyWithZone:方法");
    //使用zone参数创建一个GKHUser对象
    GKHUser *user = [[[self class] allocWithZone:zone] init];

    user.name = self.name;//这里只是浅复制
    user.age = self.age;
    return user;
}
@end


main.m

[code]#import <Foundation/Foundation.h>
#import "GKHUser.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        GKHUser *user1 = [GKHUser new];
        user1.name = [NSMutableString stringWithString:@"李太"];
        user1.age = 10;

        GKHUser *user2 = [user1 copy];//复制不可变副本
        [user1.name appendString:@"白"];
        user2.age = 20;

        NSLog(@"user1的名字为:%@", user1.name);
        NSLog(@"user1的年龄为:%d", user1.age);
        NSLog(@"user2的名字为:%@", user2.name);
        NSLog(@"user2的年龄为:%d", user2.age);

        GKHUser *user3 = [GKHUser new];
        user3.name = [NSMutableString stringWithString:@"张大"];
        user3.age = 30;

        GKHUser *user4 = [user3 mutableCopy];//复制可变副本
        [user3.name appendString:@"彪"];
        user4.age = 40;

        NSLog(@"user3的名字为:%@", user3.name);
        NSLog(@"user3的年龄为:%d", user3.age);
        NSLog(@"user4的名字为:%@", user4.name);
        NSLog(@"user4的年龄为:%d", user4.age);

    }
    return 0;
}


运行main.m结果:

执行copyWithZone:方法 

user1的名字为:李太白 

user1的年龄为:10 

user2的名字为:李太白 

user2的年龄为:20 

执行mutableCopyWithZone:方法 

user3的名字为:张大彪 

user3的年龄为:30 

user4的名字为:张大彪 

user4的年龄为:40

我们从结果中发现,不管是可变复制还是不可变复制,最后修改副本的name属性时候,会导致原始对象的属性也发生修改,为什么呢?因为这里的copyWithZone:和mutableWithZone:方法中对name属性的赋值是浅复制,如下图:



为了达到我们的效果,GKHUser.h和main.m代码不变,而 GKHUser.m 修改如下: 

GKHUser.m

[code]#import "GKHUser.h"

@implementation GKHUser

//重写copyWithZone:方法
- (id) copyWithZone:(NSZone *)zone {
    NSLog(@"执行copyWithZone:方法");
    //使用zone参数创建一个GKHUser对象
    GKHUser *user = [[[self class] allocWithZone:zone] init];

    user.name = [self.name copy];//这里对name指向的对象执行深复制,复制的副本为不可变的字符串
    user.age = self.age;
    return user;
}

//重写mutableCopyWithZone:方法
- (id) mutableCopyWithZone:(NSZone *)zone {
    NSLog(@"执行mutableCopyWithZone:方法");
    //使用zone参数创建一个GKHUser对象
    GKHUser *user = [[[self class] allocWithZone:zone] init];

    user.name = [self.name mutableCopy];//这里对name指向的对象执行深复制,复制的副本为可变的字符串
    user.age = self.age;
    return user;
}
@end


运行main.m结果:

执行copyWithZone:方法 

user1的名字为:李太白 

user1的年龄为:10 

user2的名字为:李太 

user2的年龄为:20 

执行mutableCopyWithZone:方法 

user3的名字为:张大彪 

user3的年龄为:30 

user4的名字为:张大 

user4的年龄为:40

这样就达到了我们的目的,user2是user1的不可变副本,实现了copy方法,而user4是user3的可变副本,实现了mutableCopy方法。 

其在内存中的示意图如下:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yusirxiaer

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

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

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

打赏作者

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

抵扣说明:

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

余额充值