第22條:理解NSCopying協議

weixin_33860722發表於2018-09-23

使某個類支援拷貝功能,只需宣告該類遵從NSCopying協議,並且實現copyWithZone方法即可。

- (id)copyWithZone:(NSZone *)zone
注意:
為何需要NSZone?
以前開發程式,會把記憶體分成不同的“區”(zone),而物件會建立在某個區裡。
現在不用了,一個程式只有一個區:“預設區”(default zone)。
不必在擔心其中的zone引數。
// 標頭檔案:
#import <Foundation/Foundation.h>

@interface EOCPerson : NSObject <NSCopying>

@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName;

- (id)initWithFirstName:(NSString *)firstName
            andLastName:(NSString *)lastName;

- (void)addFriend:(EOCPerson *)person;
- (void)removeFriend:(EOCPerson *)person;

@end

// 實現檔案:
#import "EOCPerson.h"

@implementation EOCPerson {
    NSMutableSet *_friends;
}

- (id)initWithFirstName:(NSString *)firstName
            andLastName:(NSString *)lastName
{
    if ((self = [super init])) {
        _firstName = [firstName copy];
        _lastName = [lastName copy];
        _friends = [NSMutableSet new];
    }
    return self;
}

- (void)addFriend:(EOCPerson *)person
{
    [_friends addObject:person];
}

- (void)removeFriend:(EOCPerson *)person
{
    [_friends removeObject:person];
}

- (id)copyWithZone:(NSZone *)zone
{
    EOCPerson *copy = [[[self class] allocWithZone:zone]
                                 initWithFirstName:_firstName
                                       andLastName:_lastName];
    // 使用->語法:friends不是屬性,只是一個例項變數
    // _friends是一個可變set,不能共享,需要拷貝一份,如果是不可變的,那麼是不需要拷貝的。
    copy->_friends = [_friends mutableCopy];
    return copy;
}

@end

// 舉例:
EOCPerson *personA = [[EOCPerson alloc] initWithFirstName:@"Tom" andLastName:@"Too"];

EOCPerson *personB = [[EOCPerson alloc] initWithFirstName:@"Mark" andLastName:@"Moo"];
EOCPerson *personC = [[EOCPerson alloc] initWithFirstName:@"Yar" andLastName:@"Yoo"];

[personA addFriend:personB];
[personA addFriend:personC];

EOCPerson *copyPersonA = [personA copy];

通常情況,採用全能初始化方法來初始化拷貝的物件,但有時,會有一些“副作用”。

如果自定義物件還有可變版本,那麼需要遵從NSMutableCopying協議,並實現mutableCopyWithZone方法

- (id)mutableCopyWithZone:(NSZone *)zone;

淺拷貝:Foundation框架中所有collection類在預設情況下都是執行淺拷貝,只拷貝容器物件本身,而不復制其中的資料。

深拷貝:在拷貝容器物件自身時,也將其底層資料一併複製一份過去。

如果所寫的物件需要深拷貝,那麼可以考慮新增一個專門執行深拷貝的方法。


1294138-6100c7ec6fff1fc4.jpg
淺拷貝與深拷貝對比圖.jpg

相關文章