NSCopying&NSMutableCopying protocol
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end
copy&mutableCopy
- (id)copy;
- (id)mutableCopy;
总结:
- copy和mutableCopy是NSObject方法成员,因此任何继承自NSObject的类都可调用
- copy调用copyWithZone,mutableCopy调用mutableCopyWithZone
- NSObject并没有实现NSCopying和NSMutableCopying,因此类如果没有遵守NSCopying和NSMutableCopying,调用copy和mutableCopy会crash
预定义NSCopying&NSMutableCopying区别
- (void)immutable_mutable
{
NSArray *imArray = [NSArray arrayWithObjects:@"dog", nil];
id imArray_im = [imArray copy];
id imArray_m = [imArray mutableCopy];
NSLog(@"imArray addr = %p, imArray RC = %ld, imArray type = %s", imArray, [imArray retainCount], object_getClassName(imArray));
NSLog(@"imArray_im addr = %p, imArray_im RC = %ld, imArray_im type = %s", imArray_im, [imArray_im retainCount], object_getClassName(imArray_im));
NSLog(@"imArray_m addr = %p, imArray_m RC = %ld, imArray_m type = %s", imArray_m, [imArray_m retainCount], object_getClassName(imArray_m));
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"dog", nil];
id mArray_im = [mArray copy];
id mArray_m = [mArray mutableCopy];
NSLog(@"mArray addr = %p, mArray RC = %ld, mArray type = %s", mArray, [mArray retainCount], object_getClassName(mArray));
NSLog(@"mArray_im addr = %p, mArray_im RC = %ld, mArray_im type = %s", mArray_im, [mArray_im retainCount], object_getClassName(mArray_im));
NSLog(@"mArray_m addr = %p, mArray_m RC = %ld, mArray_m type = %s", mArray_m, [mArray_m retainCount], object_getClassName(mArray_m));
}
output:
imArray addr = 0x7fd4a3cc3190, imArray RC = 2, imArray type = __NSArrayI
imArray_im addr = 0x7fd4a3cc3190, imArray_im RC = 2, imArray_im type = __NSArrayI
imArray_m addr = 0x7fd4a3cbf8a0, imArray_m RC = 1, imArray_m type = __NSArrayM
mArray addr = 0x7fd4a3cb9050, mArray RC = 1, mArray type = __NSArrayM
mArray_im addr = 0x7fd4a3cc59b0, mArray_im RC = 1, mArray_im type = __NSArrayI
mArray_m addr = 0x7fd4a3cc2720, mArray_m RC = 1, mArray_m type = __NSArrayM
总结:
- 不管immutable实例对象还是mutable实例对象,copy返回immutable实例对象,mutableCopy返回mutable实例对象
- immutable实例对象,copy返回的immutable实例对象和original实例对象指向同一实例对象,相当于retain或strong,即引用计数+1
自定义NSCopying&NSMutableCopying
@interface FBAnimal : NSObject <NSCopying, NSMutableCopying>
{
NSString *_name;
}
- (instancetype)initName:(NSString *)name;
@end
@implementation FBAnimal
- (instancetype)initName:(NSString *)name
{
self = [super init];
if(self)
{
_name = [NSString stringWithString:name];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
NSLog(@"class %s copy", object_getClassName(self));
[self->_name copy];
[self retain];
return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
NSLog(@"class %s mutableCopy", object_getClassName(self));
FBAnimal *animal = [[[self class] allocWithZone:zone] init];
animal->_name = [self->_name copy];
return animal;
}
@end
@interface FBDog : FBAnimal
{
NSString *_breed;
}
- (instancetype)initBreed:(NSString *)breed;
@end
@implementation FBDog
- (instancetype)initBreed:(NSString *)breed
{
self = [super initName:@"dog"];
if(self)
{
_breed = [NSString stringWithString:breed];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
self = [super copyWithZone:zone];
[self->_breed copy];
return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
FBDog *dog = [super mutableCopyWithZone:zone];
[dog->_breed copy];
return dog;
}
@end
- (void)immutable_mutable
{
FBAnimal *animal = [[FBAnimal alloc] initName:@"animal"];
id animal_im = [animal copy];
id animal_m = [animal mutableCopy];
NSLog(@"animal addr = %p, animal RC = %ld, animal type = %s", animal, [animal retainCount], object_getClassName(animal));
NSLog(@"animal_im addr = %p, animal_im RC = %ld, animal_im type = %s", animal_im, [animal_im retainCount], object_getClassName(animal_im));
NSLog(@"animal_m addr = %p, animal_m RC = %ld, animal_m type = %s", animal_m, [animal_m retainCount], object_getClassName(animal_m));
FBDog *dog = [[FBDog alloc] initBreed:@"husky"];
id dog_im = [dog copy];
id dog_m = [dog mutableCopy];
NSLog(@"dog addr = %p, dog RC = %ld, dog type = %s", dog, [dog retainCount], object_getClassName(dog));
NSLog(@"dog_im addr = %p, dog_im RC = %ld, dog_im type = %s", dog_im, [dog_im retainCount], object_getClassName(dog_im));
NSLog(@"dog_m addr = %p, dog_m RC = %ld, dog_m type = %s", dog_m, [dog_m retainCount], object_getClassName(dog_m));
}
output:
class FBAnimal copy
class FBAnimal mutableCopy
animal addr = 0x7ff1d0d16280, animal RC = 2, animal type = FBAnimal
animal_im addr = 0x7ff1d0d16280, animal_im RC = 2, animal_im type = FBAnimal
animal_m addr = 0x7ff1d0d18000, animal_m RC = 1, animal_m type = FBAnimal
class FBDog copy
class FBDog mutableCopy
dog addr = 0x7ff1d0d19300, dog RC = 2, dog type = FBDog
dog_im addr = 0x7ff1d0d19300, dog_im RC = 2, dog_im type = FBDog
dog_m addr = 0x7ff1d0d1a330, dog_m RC = 1, dog_m type = FBDog
@property的copy修饰词
- (void)property_copy
{
FBAnimal *animal = [[FBAnimal alloc] initName:@"animal"];
FBDog *dog = [[FBDog alloc] initBreed:@"husky"];
FBFarm *farm = [[FBFarm alloc] init];
farm.animal = animal;
farm.dog = dog;
}
output:
class FBAnimal copy
class FBDog copy
结论:
- @property的copy修饰符本质就是调用setter时,调用实例对象(setter参数)copy,copy调用copyWithZone,因此property对应类型必须遵守NSCopying