第22條:理解NSCopying協(xié)議
1. NSCopying協(xié)議
如果想令自己的類支持拷貝操作嘴高,必須實(shí)現(xiàn)NSCopying協(xié)議贸呢,該協(xié)議只有一個(gè)方法:
- (id)copyWithZone:(NSZone *)zone
如果沒實(shí)現(xiàn)該協(xié)議奏司,會(huì)拋出異常伸刃,如:
2. 例子
EOCPerson類
/* EOCPerson頭文件 */
#import <Foundation/Foundation.h>
@interface EOCPerson : NSObject<NSCopying> // 遵守NSCopying協(xié)議
@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
/* EOCPerson實(shí)現(xiàn)文件 */
#import "EOCPerson.h"
@implementation EOCPerson{
// 實(shí)例變量
NSMutableSet *_friends;
}
- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName{
if (self = [super init]) {
_firstName = firstName;
_lastName = lastName;
_friends = [NSMutableSet new]; // 延遲初始化
}
return self;
}
- (void)addFriend:(EOCPerson *)person{
[_friends addObject:person];
}
- (void)removeFriend:(EOCPerson *)person{
[_friends removeObject:person];
}
// 要想該類能夠?qū)崿F(xiàn)拷貝操作必須實(shí)現(xiàn)copyWithZone:方法
- (id)copyWithZone:(NSZone *)zone{
// 拷貝對象
EOCPerson *copy = [[[self class] allocWithZone:zone]
initWithFirstName:_firstName
andLastName:_lastName];
// 拷貝對象的實(shí)例變量
copy->_friends = [_friends mutableCopy];
return copy;
}
- (NSString *)description{
return [NSString stringWithFormat:@"%@ %@", _firstName, _lastName];
}
@end
main函數(shù)
#import <Foundation/Foundation.h>
#import "EOCPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
EOCPerson *person = [[EOCPerson alloc] initWithFirstName:@"Bob" andLastName:@"Smith"];
EOCPerson *person2 = [[EOCPerson alloc] initWithFirstName:@"Bill" andLastName:@"Jobs"];
EOCPerson *person3 = [[EOCPerson alloc] initWithFirstName:@"Scot" andLastName:@"Hotway"];
EOCPerson *person4 = [person copy];
[person4 addFriend:person2];
[person4 addFriend:person3];
NSLog(@"person4 = %@",person4);
}
return 0;
}
輸出結(jié)果:
person4 = Bob Smith
3. 深拷貝與淺拷貝
- 深拷貝:在拷貝對象自身時(shí)谎砾,將其底層數(shù)據(jù)也一并復(fù)制過去。
- 淺拷貝:只拷貝collection容器對象本身捧颅,而不復(fù)制其中數(shù)據(jù)景图。
在自定義的類中,通常以淺拷貝的方式實(shí)現(xiàn)“copyWithZone:”方法碉哑。若想實(shí)現(xiàn)深拷貝挚币,需要增加一個(gè)執(zhí)行深拷貝的方法。NSSet類提供了下面這個(gè)初始化方法扣典,用以執(zhí)行深拷貝妆毕,如:
- (instancetype)initWithSet:(NSSet<ObjectType> *)set copyItems:(BOOL)flag
在上面的EOCPerson例子中,若需要深拷貝的話贮尖,則需要編寫一個(gè)專供深拷貝所用的方法:
- (id)deepCopy{
EOCPerson *copy = [[[self class] alloc]
initWithFirstName:_firstName
andLastName:_lastName];
copy->_friends = [[NSMutableSet alloc] initWithSet:_friends copyItems:YES];
return copy;
}
要點(diǎn)
- 若想令自己所寫的對象具有拷貝功能笛粘,則需實(shí)現(xiàn)NSCopying協(xié)議。
- 如果自定義的對象分為可變版本與不可變版本远舅,那么就要同時(shí)實(shí)現(xiàn)NSCopying與NSMutableCopying協(xié)議闰蛔。
- 復(fù)制對象時(shí)需決定采用淺拷貝還是深拷貝,一般情況下應(yīng)該盡量執(zhí)行淺拷貝图柏。
- 如果你所寫的對象需要深拷貝,那么可考慮新增一個(gè)專門執(zhí)行深拷貝的方法任连。