IOS 拷贝

本文深入探讨Objective-C中的copy与mutableCopy的区别,解析retain与copy的行为差异,并提供了如何正确实现NSCopying与NSMutableCopying协议的示例。

1.copy vs mutableCopy

copy,对于不可变的对象,简单的指向其内存.对于可变对象,复制内存内容到新的内存中并把新的内存值赋值给左值.

mutableCopy,始终复制到新的内存中,以一个可变的类型赋值给左值.

 

2.copy vc retain

retain,引用计数+1,内存地址赋值给左值.

copy,对于不可变对象的,相当于retain;对于可变对象,则是深拷贝赋值.

举例:

    NSString* a = [NSString stringWithFormat:@"%@",@"this is a"];    NSString* b = [a copy];    NSString* bb = [a retain];    NSString* cc = [a mutableCopy];//实际上cc应该是NSMutableString类型    NSLog(@"%d,%d,%d,%d",[a retainCount],[b retainCount],[bb retainCount],[cc retainCount]);//输出3,3,3,1    NSMutableString* a = [NSMutableString stringWithFormat:@"%@",@"this is a"];    NSString* b = [a copy];//不可变的b    NSString* bb = [a retain];//实际类型是NSMutableString的bb    NSString* cc = [a mutableCopy];//同上    NSLog(@"%d,%d,%d,%d",[a retainCount],[b retainCount],[bb retainCount],[cc retainCount]);//输出2,1,2,1
3.一些问题

通过上面2点,思考下面的问题

我们通常如果这样定义一个变量

@property(nonatomic,copy)  NSMutableString* mString;然后这样使用

@synthesize mString;NSMutableString* a = [NSMutableString stringWithFormat:@"%@",@"this is a"];self.mString = a;[mString insertString:@"m-" atIndex:0];
能通过么?当然不能,赋值后的mString是NSString类型的,不可变.如果需要可以改变就需要自己定义属性函数.

-(void)setMString:(NSMutableString *)m{    mString = [m mutableCopy];}-(NSMutableString *)mString{    return mString;}(当然,NSMutableString不是线程安全的,一般都建议私有之:@private;或者一定要用的话以NSString作为对外接口类型)

4.NSCopying NSMutableCopying NSCopyObjective()

NSCopying就是复制一个对象

NSMutableCopying就是深拷贝一个对象,让两个对象的改变互不影响

(其实上面着两个完全看你怎么写啦)

NSCopyObject(self,0,zone)就是简单的赋值=

(在涉及到ns对象的时候,NSCopyObject不建议使用)

注意看下面一个例子:

@interface ClassB : NSObject <NSCopying>{    NSString* stringB;}@property(nonatomic,copy) NSString* stringB;@end-(id)copyWithZone:(NSZone *)zone{    ClassB *b = NSCopyObject(self, 0, zone);// 使用NSCopyObject时的正确赋值方法,因为没有涉及到原来的内存指针什么事    b->stringB = @"what";// 看看被注释的这个错误方法,由于setter方法的特性,原来的stringB指向的内存的retainCount减一// 而由于NSCopyObject的特性,两者又是指向同一个地址的,所以,原类中stirngB指向的地址已经释放了,之后你dealloc中在释放一次?!.就出错啦//    b.stringB = @"what";    return b;}

 

参考:http://stackoverflow.com/questions/2002174/copy-mutablecopy

http://stackoverflow.com/questions/4995254/nsmutablestring-as-retain-copy

http://robnapier.net/blog/implementing-nscopying-439#comment-1312
注释:可变对象mutable比如NSMutableString,NSMutableArray等
       不可变对象immutable比如NSString,NSArray等

<think>好的,我现在需要回答用户关于iOS深浅拷贝的问题。首先,我得确保自己理解深浅拷贝的基本概念,以及在iOS中的具体实现和应用场景。 首先,深拷贝和浅拷贝的区别是什么?浅拷贝应该是指复制对象的指针,而不是实际数据,所以新旧对象共享同一份数据。而深拷贝则是完全复制数据,新对象和原对象独立,修改互不影响。这在内存管理中很重要,尤其是在处理集合类型如NSArray、NSDictionary时。 接下来,我需要考虑在iOS中,哪些对象默认是浅拷贝,哪些支持深拷贝。比如,使用copy方法时,不可变对象如NSArray可能返回自身(浅拷贝),而可变对象如NSMutableArray会生成新的不可变副本。但这里的copy是否是深拷贝呢?可能要看具体类的实现,比如集合的copy方法是否是浅拷贝,而深拷贝可能需要使用其他方法,比如NSKeyedArchiver。 然后,要提到NSCopying协议,因为自定义对象要实现拷贝功能必须遵循这个协议,并实现copyWithZone:方法。这里可能需要区分浅拷贝和深拷贝的实现方式,比如在复制属性时是直接赋值(浅)还是创建新实例(深)。 还需要举例说明,比如NSString、NSArray等系统类的情况,以及自定义类如何处理。同时,可能需要注意可变和不可变版本的区别,比如NSMutableArray的copy和mutableCopy的不同行为。 另外,内存管理方面,ARC自动处理引用计数,但理解深浅拷贝对内存的影响仍然重要,避免不必要的内存泄漏或重复数据。 可能用户还想知道如何选择深拷贝或浅拷贝,比如在需要独立数据时使用深拷贝,否则使用浅拷贝节省内存。同时,可以提到常见的深拷贝方法,如归档解档(NSKeyedArchiver)、手动复制每个元素等。 最后,检查是否有遗漏点,比如集合对象的元素是否被深拷贝。例如,NSArray的copy是浅拷贝,所以内部的元素还是原来的,如果元素是可变对象,修改它们会影响新旧数组。这时候需要实现真正的深拷贝可能需要遍历每个元素进行复制。 总结回答的结构应该包括:定义、区别、系统类的行为、自定义类的实现、深浅拷贝的选择以及注意事项。确保用中文,结构清晰,例子恰当,语法正确,数学公式用指定格式。</think>在 iOS 开发中,**深拷贝(Deep Copy)**和**浅拷贝(Shallow Copy)**是对象复制的两种重要方式,理解它们的区别对内存管理和数据独立性至关重要。 --- ### 1. 基本概念 - **浅拷贝** 仅复制对象的指针,新旧对象**共享同一份底层数据**。修改其中一个对象的内容,另一个会受影响。 **示例**: ```objective-c NSArray *original = @[@1, @2, @3]; NSArray *shallowCopy = [original copy]; // 浅拷贝(不可变对象的 copy 是浅拷贝) ``` - **深拷贝** 完全复制对象及其底层数据,生成**独立的新对象**。修改其中一个对象不会影响另一个。 **示例**: ```objective-c NSArray *original = @[@1, @2, @3]; NSArray *deepCopy = [[NSArray alloc] initWithArray:original copyItems:YES]; // 深拷贝 ``` --- ### 2. 系统类的默认行为 - **不可变对象(如 `NSString`, `NSArray`)** - `copy` 方法返回**浅拷贝**(原对象本身,因不可变无需复制)。 - `mutableCopy` 返回**深拷贝**(生成可变对象)。 - **可变对象(如 `NSMutableString`, `NSMutableArray`)** - `copy` 和 `mutableCopy` 均返回**深拷贝**。 $$ \text{可变性决定拷贝行为:可变对象默认深拷贝,不可变对象默认浅拷贝} $$ --- ### 3. 自定义对象的拷贝 若需支持拷贝,类需遵循 **`NSCopying`** 或 **`NSMutableCopying`** 协议,并实现对应方法: ```objective-c @interface Person : NSObject <NSCopying> @property (nonatomic, copy) NSString *name; @end @implementation Person - (id)copyWithZone:(NSZone *)zone { Person *copy = [[Person alloc] init]; copy.name = self.name; // 浅拷贝(直接赋值指针) return copy; } @end ``` - **浅拷贝实现**:直接赋值属性(共享同一数据)。 - **深拷贝实现**:为每个属性创建新对象(例如 `copy.name = [self.name copy]`)。 --- ### 4. 集合对象的深拷贝陷阱 即使对 `NSArray`/`NSDictionary` 深拷贝,其内部元素的拷贝行为取决于元素类型: - **`copyItems:YES`** 仅对集合元素调用 `copy` 方法,若元素是自定义对象且未实现深拷贝,仍为浅拷贝! **完全深拷贝解决方案**: ```objective-c NSData *data = [NSKeyedArchiver archivedDataWithRootObject:originalArray]; NSArray *trueDeepCopy = [NSKeyedUnarchiver unarchiveObjectWithData:data]; ``` --- ### 5. 如何选择? | 场景 | 推荐方式 | |------|----------| | 对象不可变且无需修改 | 浅拷贝(节省内存) | | 对象需要独立修改 | 深拷贝 | | 集合对象包含可变元素 | 完全深拷贝(如归档解档) | --- ### 6. 注意事项 - 使用 `copy` 修饰符(`@property (copy)`)可防止可变对象被外部修改(如 `NSMutableString` 赋值给 `NSString`)。 - 深拷贝可能带来性能开销,需权衡内存与独立性需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值