oc——Foundation框架——对象复制

copy与mutableCopy方法

copy方法用于复制对象的副本。通常来说,copy方法总是返回对象的不可修改的副本,即使该对象本身是可修改的。例如,程序调用NSMutableString的copy方法,将会返回不可修改的字符串对象。
mutableCopy方法用于复制对象的可变副本。通常来说,mutableCopy方法总是返回该对象可修改的副本,即使被复制的对象本身是不可修改的,调用mutableCopy方法复制出来的副本也是可修改的。例如,程序调用NSString的mutableCopy方法,将会返回一个NSMutableString对象。
我们先来看下面代码:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableString * str = [NSMutableString stringWithString:@"123"];
        //先创建一个可变字符串
        NSMutableString * strcopy = [str mutableCopy];
        //复制字符串的可变副本
        [strcopy appendString:@"456"];
        NSLog(@"%@",strcopy);
        NSLog(@"%@",str);
    }
    return 0;
}

最终我们发现原字符串并没有发生改变,字符串副本发生了改变。
然后我们在原代码后面加上两行,创造一个不可改变的副本改变它的值试试看。

NSMutableString * strcopy2 = [str copy];
[strcopy2 appendString:@"789"];

运行会报错
在这里插入图片描述
由此可以看出对副本的改变,对原始对象不会有任何影响,并且用copy方法形成的副本是不可改变的。

NSCopying与NSMutableCopy协议

使用copy和mutablecopy复制对象的副本是否可以用于自定义的类呢?
我们自己定义一个类试试

//  FKPerson.h
#import <Foundation/Foundation.h>
@interface FKPerson : NSObject
@property (nonatomic,strong) NSMutableString * name;
@property (nonatomic,assign) int age;
@end


//  FKPerson.m
#import "FKPerson.h"
@implementation FKPerson
@synthesize name;
@synthesize age;
@end

//main.m
#import <Foundation/Foundation.h>
#import "FKPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKPerson * zhai = [[FKPerson alloc] init];
        zhai.name = [NSMutableString stringWithString:@"666"];
        zhai.age = 19;
        FKPerson * zhai2 = [zhai copy];
    }
    return 0;
}

结果显示会报错:
在这里插入图片描述
报错的原因是找不到mutableCopyWithZone:方法
为了解决这个问题,要做如下事情:
🎇让该类实现NSCopying / NSMutableCopying协议
🎇让该类实现copyWithZone / mutableCopyWithZone方法
当使用调用对象的copy方法来复制自身时,程序底层需要调用copyWithZone:方法来完成实际的复制工作,从朋友返回的实际上就是copyWithZone:方法的返回值;当程序调用对象的mutableCopy方法来复制自身时,程序底层需要调用mutableCopyWithZone:方法来完成实际的复制工作,mutableCopy返回的实际上就是mutableCopyWithZone:方法的返回值。
为了保证FKPerson类可调用copy方法来复制自身,程序可先在FKPerson类的接口上实现NSCopying协议,然后在FKPerson类的实现部分增加如下的copyWithZone:方法。

//  FKPerson.h
#import <Foundation/Foundation.h>
@interface FKPerson : NSObject <NSCopying>
@property (nonatomic,strong) NSMutableString * name;
@property (nonatomic,assign) int age;
@end

//  FKPerson.m
#import "FKPerson.h"
@implementation FKPerson
@synthesize name;
@synthesize age;
- (id)copyWithZone:(NSZone *)zone {
    NSLog(@"执行copyWithZone方法");
    FKPerson * a = [[[self class]allocWithZone:zone]init];
    a.name = self.name;
    a.age = self.age;
    return a;
}
@end

//main.m
#import <Foundation/Foundation.h>
#import "FKPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKPerson * zhai = [[FKPerson alloc] init];
        zhai.name = [NSMutableString stringWithString:@"666"];
        zhai.age = 19;
        FKPerson * zhai2 = [zhai copy];
        zhai2.name = [NSMutableString stringWithString:@"999"];
        zhai2.age = 20;
        NSLog(@"%@",zhai.name);
        NSLog(@"%d",zhai.age);
        NSLog(@"%@",zhai2.name);
        NSLog(@"%d",zhai2.age);
    }
    return 0;
}

输出结果:
在这里插入图片描述

setter方法的复制选项

在之前合成setter和getter方法的时候可以用到copy指示符,copy指示符指定程序调用setter方法复制时,实际上是将传入参数的副本赋值给程序的实例变量。
还是刚才那个FKPerson类,我们对它的接口和实现进行修改:

//  FKPerson.h
#import <Foundation/Foundation.h>
@interface FKPerson : NSObject <NSCopying>
@property (nonatomic,copy) NSMutableString * name;
@end
//  FKPerson.m
#import "FKPerson.h"
@implementation FKPerson
@synthesize name;
@end

#import <Foundation/Foundation.h>
#import "FKPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKPerson * zhai = [[FKPerson alloc] init];
        zhai.name = [NSMutableString stringWithString:@"666"];
        [zhai.name appendString:@"999"];        
    }
    return 0;
}

程序在编译时没有问题,在运行时报错:
在这里插入图片描述
这段错误提示name属性不可修改,这是因为程序定义name属性时使用了copy指示符,该指示符指定调用setName:方法,程序实际上会使用参数的副本对name实例变量赋值。
copy方法默认是复制该对象的不可变副本,虽然程序传入的NSMutableString,但程序调用该参数的copy方法得到的是不可变副本。因此,程序赋给FKPerson对象的name实例变量的值依然是不可变字符串。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值