天天看点

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

下一篇: c++ 预编译