---------- IOS培训、java培训、期待与您交流! ----------
一个对象使用copy 与 mutableCopy可以创建一个对象的副本
copy--需要实现NSCopying协议,创建的是不可变副本(如NSString,NSArray,NSDictionary)
mutableCopy---需要实现NSMutableCopying协议,创建的是可变副本(如NSMutableString,NSMutableArray,NSMutableDictionary)
用一个专业术语来描述拷贝
深拷贝:内容拷贝,源对象和副本指向的不是两个对象。源对象引用计数器不变,副本计数器设置为1。
浅拷贝:指针拷贝,源对象和副本指向的是同一个对象。对象引用计数器加1,相当于做了一次retain操作。
只有不可变对象创建不可变副本的时候才是浅拷贝,其它任何时候都是深拷贝。---即,当对象不同的时候就一定是深拷贝。
#pragma mark 演示字符串的拷贝(浅拷贝)
// 只有一种情况是浅拷贝:不可变对象调用copy方法时
// 浅拷贝:指针拷贝,不会产生新的对象。源对象计数器+1。
void stringCopy() {
NSString *string = [[NSString alloc] initWithFormat:@"age is %i", 10];
NSLog(@"%zi", [string retainCount]);
// copy产生的是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy会直接返回源对象本身
// 源对象计数器会+1
// 在浅拷贝情况下,copy其实就相当于retain
NSString *str = [string copy];
NSLog(@"%zi", [string retainCount]);
// NSLog(@"%i", str == string);
[str release];
[string release];
}
#pragma mark mutableStringMutablecopy
void mutableStringMutableCopy(){
NSMutableString* str1= [NSMutableString stringWithFormat:@"hello world %i",2015];
//[str1 appendFormat:@"hello world"];
NSMutableString* str2= [str1 mutableCopy];
[str2 appendString:@" haha"];
NSLog(@"str1%@",str1);
NSLog(@"str2%@",str2);
[str2 release];
}
得到
2015-03-04 11:52:23.001 CopyAndMutableCopy[884:40088] str1hello world 2015
2015-03-04 11:52:23.002 CopyAndMutableCopy[884:40088] str2hello world 2015 haha
Program ended with exit code: 0
可以看出可变字符串的mutablecopy得到的另一个可变字符串,两者之间只是内容间的拷贝。修改str2,并不会改变str1的值。
下面我们通过代码来阐述对象间的copy方法。-----------
首先我们定义一个简单的类。如car类
在car.h中,我们做如下声明
#import <Foundation/Foundation.h>
@interface Car : NSObject <NSCopying>
@property (nonatomic,copy)NSString * brand;
@property(nonatomic,assign)int speed;
+(id)carBrand:(NSString*)brand withSpeed:(int)speed;
@end
//
// Car.m
// CopyAndMutableCopy
//
// Created by 肖俊全 on 15/3/3.
// Copyright (c) 2015年 肖俊全. All rights reserved.
//
#import "Car.h"
@implementation Car
+(id)carBrand:(NSString *)brand withSpeed:(int)speed{
Car * car=[[[[self class] alloc ]init]autorelease];
car.brand =brand;
car.speed= speed;
return car;
}
-(id)copyWithZone:(NSZone *)zone{
//如果子类拷贝,则一定要写【self class】
Car *copy = [[self class]allocWithZone:zone];//这里内存不用释放。因为后面会调用coy release方法
copy.brand=self.brand;
copy.speed=self.speed;
return copy;
}
-(void)dealloc{
[_brand release];
NSLog(@"%@被回收了",self.brand );
[super dealloc];
}
-(NSString *)description{
return [NSString stringWithFormat:@"brand is %@,speed is %i",_brand,_speed];
}
@end
主函数中:
#import <Foundation/Foundation.h>
#import "Car.h"
#import "Bus.h"
#pragma mark carCopy
void carCopy(){
Car * c1=[Car carBrand:@"baoma" withSpeed:300];
Car *c2=[c1 copy];
c2.brand = @"hanma";
NSLog(@"c1=%@",c1);
NSLog(@"c2=%@",c2);
[c2 release];
}
然后在main当中,直接调用carCopy();即可。我们得到。
2015-03-04 11:58:29.727 CopyAndMutableCopy[933:45912] c1=brand is baoma,speed is 300
2015-03-04 11:58:29.728 CopyAndMutableCopy[933:45912] c2=brand is hanma,speed is 300
2015-03-04 11:58:29.728 CopyAndMutableCopy[933:45912] hanma被回收了
2015-03-04 11:58:29.729 CopyAndMutableCopy[933:45912] baoma被回收了
Program ended with exit code: 0
可以看到。我们对c1的copy,得到c2,再对c2的brand品牌属性进行更改并不会改变c1的值。最后对象回收,调用对象的dealloc方法。可知没有资源的泄漏。
如果我们在car的基础之上,再派生出一个之类。并在子类对象间进行拷贝。我们应该怎么做呢。
定义一个bus类。
#import "Car.h"
@interface Bus : Car
@property(nonatomic,copy)NSString * name;
+(id)busBrand:(NSString *)brand withSpeed:(int)speed andName:(NSString *)name;
@end
bus.m文件
#import "Bus.h"
@implementation Bus
+(id)busBrand:(NSString *)brand withSpeed:(int)speed andName:(NSString *)name{
Bus * bus = [Bus carBrand:brand withSpeed:speed];
bus.name=name;
return bus;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
-(id)copyWithZone:(NSZone *)zone{
//一定要调用父类的方法
Bus *bus= [super copyWithZone:zone];
bus.name=self.name;
return bus;
}
-(NSString *)description{
return [NSString stringWithFormat:@"brand is %@,speed is %i,name is %@",self.brand,self.speed,self.name];
}
@end
#pragma mark busCopy
void busCopy(){
Bus *b1=[Bus busBrand:@"JingGang" withSpeed:200 andName:@"bigJingGang"];
Bus *b2=[b1 copy];
b2.name=@"hahaJingGang";
NSLog(@"b1=%@",b1);
NSLog(@"c2=%@",b2);
[b2 release];
}
一样的main函数直接调用busCopy(); 方法运行得到:
2015-03-04 12:03:24.254 CopyAndMutableCopy[964:50733] b1=brand is JingGang,speed is 200,name is bigJingGang
2015-03-04 12:03:24.255 CopyAndMutableCopy[964:50733] c2=brand is JingGang,speed is 200,name is hahaJingGang
2015-03-04 12:03:24.255 CopyAndMutableCopy[964:50733] JingGang被回收了
2015-03-04 12:03:24.255 CopyAndMutableCopy[964:50733] JingGang被回收了
Program ended with exit code: 0
可以方现。我们并没有在bus.m文件中的dealloc方法中写资源回收。其实这里调用的是super的dealloc方法,因为bus继承自car。
并且,我们看似很容易就实现了子类对象的copy方法。这里需要注意的是。子类如果要用到父类的类方法,以及copy父类的一些属性。则父类中,不能写死,
如写成 Car *copy = [car allocWithZone:zone]; 而应该写成 Car *copy = [[self class]allocWithZone:zone];
包括初始化对象的时候应该写成 Car * car=[[[[self class] alloc ]init]autorelease]; 方便子类调用。使得程序做到低偶合,高内聚。