OC学习深浅拷贝

浅拷贝:只拷贝引用(指针), 不拷贝对象空间(不创建新的对象空间,只是使对象的引用计数器加1)
深拷贝:不拷贝引用,拷贝的是整个对象空间,即拷贝时会创建新的对象空间,空间内容和原来内容相同。

copy mutableCopy对于自定义对象是一样的
copy mutableCopy对于系统的基本类是有区别的
NSString NSMutableString NSArray NSMutableArray NSDictionary NSMutableDictionary NSSet NSMutableSet NSData NSMutableData

拷贝对象的时候要向对象发送copy或mutableCopy消息,执行copy或mutableCopy的对象必须要遵守NSCopying协议或NSMutableCopying协议,并实现里面的方法:copyWithZone:或mutableCopyWithZone:

系统的一些类之所以可以copy或mutableCopy,只因为这个类本身已经遵守了协议并实现了协方法,我们可以直接对其copy或mutableCopy, 但是我们自定义的类如果想要 copy ,就要遵守协议并实现协议方法。对于自定义的类或系统的其他类是没有可变和不可变之说的,copy和mutableCopy的功能是一样的。

系统类的copy
NSArray *array = [NSArray arrayWithObjects:@"one", @"two", nil];
NSLog(@"array == address: %p retainCount: %ld", array, array.retainCount);
NSArray *array2 = [array copy];
NSLog(@"array2 == address: %p retainCount: %ld", array2, array2.retainCount);

// Foundation基础类,字符串,数组,字典,集合,不可变类,调用copy,是浅拷贝,甚至可以理解为它的作用相当于retain
// 注意这里浅拷贝有两个条件:
// 第一是这些Foundation基础类
// 第二是不可变对象
// 第二是调用copy方法

NSMutableArray *mArr = [[NSMutableArray alloc] initWithObjects:@"dog", @"cat", nil];
NSLog(@"mArr == address: %p retainCount: %ld", mArr, mArr.retainCount);
NSMutableArray *mArr2 = [mArr copy];
NSLog(@"mArr2 == address: %p retainCount: %ld", mArr2, mArr2.retainCount);
// 总结:对于系统的这些可变对象,调用copy时,是深拷贝,对象的内容被copy


————————————————————————

自定义对象的copy

#import <Foundation/Foundation.h>

@interface Dog : NSObject <NSCopying, NSMutableCopying>

@property (nonatomic) NSInteger age;
@property (nonatomic) NSInteger height;
@end


#import "Dog.h"

@implementation Dog

// 调用copy的时候自动调用
- (id)copyWithZone:(NSZone *)zone {
    return [self retain]; // 不会创建新的对象,只是让对象的引用计数器加1
}

// 调用mutableCopy的时候自动调用
- (id)mutableCopyWithZone:(NSZone *)zone {
    return [self retain];
}

- (void)dealloc {
    NSLog(@"Dog dealloc");
    [super dealloc];
}

@end

#import <Foundation/Foundation.h>
#import "Dog.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog *dog = [[Dog alloc] init];
        dog.age = 2;
        dog.height = 170;
        NSLog(@"dog: %p retainCount: %ld", dog, dog.retainCount);
        Dog *newDog = [dog copy];
        NSLog(@"newDog: %p retainCount: %ld", newDog, newDog.retainCount);
    }
    return 0;
}

————————————————————————

对于自定义类的深拷贝,需要创建新的空间,并把原来的对象的属性赋给它即可,比如对于上面的示例,如果要对dog深拷贝,就要这样实现:
// 调用copy的时候自动调用
- (id)copyWithZone:(NSZone *)zone {
    // return [self retain]; // 不会创建新的对象,只是让对象的引用计数器加1
    Dog *copyDog = [[[self class] allocWithZone:zone] init];
    copyDog.age = self.age;
    copyDog.height = self.height;
    return copyDog;
}

// 调用mutableCopy的时候自动调用
- (id)mutableCopyWithZone:(NSZone *)zone {
    // return [self retain];
    Dog *copyDog = [[[self class] allocWithZone:zone] init];
    copyDog.age = self.age;
    copyDog.height = self.height;
    return copyDog;
}

————————————————————————

注意:在自定义类的拷贝中,对于浅拷贝,在拷贝过程中,如果对象内容(对象的属性)中有其他的对象引用(指针),那么只拷贝指针引用,不拷贝指针指向的对象空间。对于深拷贝,如果对象内容(对象的属性)中有其他的对象引用,那么要拷贝掼针指向的对象空间,而不是引用。如果指针指向的对象又不其他对象指针,则继续拷贝空间,递归下去,直到拷贝到最后。那么如果有一个对象,对它深拷贝,就不仅要仅仅拷贝当前对象了,对象中如果有其他指引指向了另外一个对象,那么这个对象也应该继续深拷贝:
Car.h
#import <Foundation/Foundation.h>
#import "Engine.h"

@interface Car : NSObject <NSCopying>

@property (nonatomic) float speed;
@property (nonatomic, retain) Engine *engine;

@end


Car.m
#import "Car.h"

@implementation Car

- (id)copyWithZone:(NSZone *)zone {
    Car *copyCar = [[self class] allocWithZone:zone];
    copyCar.speed = self.speed;
    Engine *newEngine = [self.engine copy];
    copyCar.engine = newEngine;
    [newEngine release];
    // copyCar.engine = [[self.engine copy] autorelease];
    return copyCar;
}

- (void)dealloc {
    NSLog(@"car release");
    self.engine = nil;
    [super dealloc];
}

@end


Engine.h
#import <Foundation/Foundation.h>

@interface Engine : NSObject <NSCopying>

@property (nonatomic, copy) NSString *name;
@property (nonatomic) float weight;

@end


Engine.m

#import "Engine.h"

@implementation Engine

- (id)copyWithZone:(NSZone *)zone {
    Engine *copyEngine = [[[self class] allocWithZone:zone] init];
    copyEngine.name = self.name;
    copyEngine.weight = self.weight;
    return copyEngine;
}

- (void)dealloc {
    NSLog(@"engine release");
    self.name = nil;
    [super dealloc];
}

@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Engine *engine = [[Engine alloc] init];
        Car *car = [[Car alloc] init];
        car.engine = engine;
        [engine release];
        NSLog(@"car == address: %p retainCount: %ld", car, car.retainCount);
        NSLog(@"car.engine == address: %p retainCount: %ld", car.engine, car.engine.retainCount);
        
        Car *copyCar = [car copy];
        NSLog(@"copyCar == address: %p retainCount: %ld", copyCar, copyCar.retainCount);
        NSLog(@"copyCar.engine == address: %p retainCount: %ld", copyCar.engine, copyCar.engine.retainCount);
        
        [car release];
        [copyCar release];
    }
    return 0;
}


car == address: 0x10011bfb0 retainCount: 1
car.engine == address: 0x10011bdb0 retainCount: 1
copyCar == address: 0x100401c90 retainCount: 1
copyCar.engine == address: 0x100401d30 retainCount: 1
car release
engine release
car release
engine release


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值