从NSCopying协议到copy,mutableCopy

NSCopying 对应copy

想要使某个类支持拷贝功能,返回不可变对象,只需要将这个类遵从NSCopying协议并实现其中的方法即可(只有一个方法)。

///< NSZone:之前再开发程序的时候,会据此把内存分成不同的“区”(zone),而对象会创建在某个区里面。
///< 现在每个程序只有一个区“默认区(default zone)”,所以尽管必须实现这个方法,但是不必担心zone参数。
- (id)copyWithZone:(nullable NSZone *)zone;


当我们实现了NSCopying协议后,通过类对象调用copy方法时,copy方法会去调用copyWithZone方法。
注意:Foundation框架中的所有collection类在默认情况下都执行的是浅拷贝。

@interface A : NSObject 

@property (nonatomic, copy, readyonly) NSString *name;

- (instancetype)initWithName:(NSString *)name;

@end

@interface A ()

@property (nonatomic, copy, readywrite) NSString *name;

@end

@implementation A

- (id)copyWithZone:(nullable NSZone *)zone {
    ///< 这里注意:一定要使用[self class],因为指针可能实际指向的是A的子类。
    A *copyA = [[[self class] allocWithZone:zone] initWithName:_name];
    return copyA;
}

@end

NSMutableCopying 对应mutableCopy

与NSCopying协议类似,此协议对应可变对象。

- (id)mutableCopyWithZone:(nullable NSZone *)zone;
无论当前版本是否可变,如果需要获取其可变版本的拷贝,均应调用mutableCopy方法。若要获取不可变版本的拷贝,需要通过copy方法获取。
[NSMutableArray copy]  => NSArray
[NSArray mutableCopy]  => NSMutableArray

*** 注意:*** 如果自定义对象分为可变版本和不可变版本,那么需要同时实现NSCopying和NSMutableCopying协议。

在C++中有一种构造函数叫:copy构造函数哟。

copy与mutableCopy一个实例

{
        ///< copy 浅copy
        NSArray *testArray = [NSArray arrayWithObjects:@"a", nil];
        id copyArray = [testArray copy];
        NSLog(@"class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyArray class], testArray, copyArray, [testArray retainCount], [copyArray retainCount]);
        /*
         2017-02-23 10:30:04.666 test[75709:577058] class:__NSSingleObjectArrayI addr:0x61000000d6b0, 0x61000000d6b0,  retainCount:2, 2
         */
    }
    {
        ///< mutableCopy 深copy
        NSArray *testArray = [NSArray arrayWithObjects:@"a", nil];
        id copyArray = [testArray mutableCopy];
        NSLog(@"class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyArray class], testArray, copyArray, [testArray retainCount], [copyArray retainCount]);
        /*
         2017-02-23 10:30:04.667 test[75709:577058] class:__NSArrayM addr:0x61000000d6e0, 0x610000055270,  retainCount:1, 1
         */
    }
    {
        ///< copy 深copy
        NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"a", nil];
        id copyArray = [testArray copy];
        NSLog(@"class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyArray class], testArray, copyArray, [testArray retainCount], [copyArray retainCount]);
        /*
         2017-02-23 10:33:20.071 test[75737:579793] class:__NSSingleObjectArrayI addr:0x61000005cce0, 0x610000009de0,  retainCount:1, 1
         */
    }
    {
        ///< mutableCopy 深copy
        NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"a", nil];
        id copyArray = [testArray mutableCopy];
        NSLog(@"class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyArray class], testArray, copyArray, [testArray retainCount], [copyArray retainCount]);
        /*
         2017-02-23 10:34:48.538 test[75753:581049] class:__NSArrayM addr:0x61000005ef30, 0x61000005f290,  retainCount:1, 1
         */
    }
从NSCopying协议到copy,mutableCopy_第1张图片
image.png

深copy 与 浅copy

深copy:当一个类拥有资源,当这个类的对象(资源)发生复制的过程。(copy完后的对象与被copy对象相互独立,不会相互影响)
浅copy:复制过程中并未复制资源的情况。

property 中的copy(内存语意)

先release旧值,再copy新值。复制一个对象并创建strong关联。copy的本质为复制该内存所存储的内容,重新创建一个对象赋给其相同的内容。
通俗点:copy一个新对象,新对象引用计数+1,原对象不变。

在NSString,NSArray,NSDictionary等 经常使用copy关键字,why?(这个问题被说烂了吧)

由于他们都对应有Mutable版本。
在实际使用时,父类的指针可以指向对应子类的对象,我们使用copy的牧师是为了让本对象的属性不受外界影响,使用copy无论给我传入的是一个可变对象还是不可变对象,我本身持有的就是一个不可变的副本。
如果我们使用strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改,那么会影响该属性值。
相关测试:

{
        NSMutableArray *testArray1 = [NSMutableArray arrayWithObjects:@"a", nil];
        NSMutableArray *testArray2 = [NSMutableArray arrayWithObjects:@"a", nil];
        NSMutableArray *testArray3 = [NSMutableArray arrayWithObjects:@"a", nil];
        NSMutableArray *testArray4 = [NSMutableArray arrayWithObjects:@"a", nil];
        NSArray *testArray5 = [[[NSArray alloc] initWithObjects:@"a", nil] autorelease];
        NSArray *testArray6 = [[[NSArray alloc] initWithObjects:@"a", nil] autorelease];
        NSArray *testArray7 = [[[NSArray alloc] initWithObjects:@"a", nil] autorelease];
        NSArray *testArray8 = [[[NSArray alloc] initWithObjects:@"a", nil] autorelease];
        YLPCopyTest *copyTest      = [[[YLPCopyTest alloc] init] autorelease];
//        copyTest.testCopyArray     = testArray1;
//        copyTest.testStrongArray   = testArray2;
//        copyTest.testCopyMutableArray   = testArray3;
//        copyTest.testStrongMutableArray = testArray4;
//        NSLog(@"testCopyArray NSMutableArray testArray1  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testCopyArray class], copyTest.testCopyArray, testArray1, [copyTest.testCopyArray retainCount], [testArray1 retainCount]);
//        NSLog(@"testStrongArray NSMutableArray testArray2  strong class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testStrongArray class], copyTest.testStrongArray, testArray2, [copyTest.testStrongArray retainCount], [testArray2 retainCount]);
//        NSLog(@"testCopyMutableArray NSMutableArray testArray3  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testCopyMutableArray class], copyTest.testCopyMutableArray, testArray3, [copyTest.testCopyMutableArray retainCount], [testArray3 retainCount]);
//        NSLog(@"testStrongMutableArray NSMutableArray testArray4  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testStrongMutableArray class], copyTest.testStrongMutableArray, testArray4, [copyTest.testStrongMutableArray retainCount], [testArray4 retainCount]);
//        /*
//         2017-02-23 11:28:47.455 test[76488:627094] testCopyArray NSMutableArray testArray1  copy class:__NSSingleObjectArrayI addr:0x618000006350, 0x61800005d8e0,  retainCount:1, 1
//         2017-02-23 11:28:47.456 test[76488:627094] testStrongArray NSMutableArray testArray2  strong class:__NSArrayM addr:0x61800005da60, 0x61800005da60,  retainCount:2, 2
//         2017-02-23 11:28:47.456 test[76488:627094] testCopyMutableArray NSMutableArray testArray3  copy class:__NSSingleObjectArrayI addr:0x618000006320, 0x61800005dc40,  retainCount:1, 1
//         2017-02-23 11:28:47.456 test[76488:627094] testStrongMutableArray NSMutableArray testArray4  copy class:__NSArrayM addr:0x61800005dc10, 0x61800005dc10,  retainCount:2, 2
//         */
        copyTest.testCopyArray     = testArray5;
        copyTest.testStrongArray   = testArray6;
        copyTest.testCopyMutableArray = testArray7;
        copyTest.testStrongMutableArray = testArray8;
        NSLog(@"testCopyArray NSArray testArray5  strong class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testCopyArray class], copyTest.testCopyArray, testArray5, [copyTest.testCopyArray retainCount], [testArray5 retainCount]);
        NSLog(@"testStrongArray NSArray testArray6  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testStrongArray class], copyTest.testStrongArray, testArray6, [copyTest.testStrongArray retainCount], [testArray6 retainCount]);
        NSLog(@"testCopyMutableArray NSArray testArray7  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testCopyMutableArray class], copyTest.testCopyMutableArray, testArray7, [copyTest.testCopyMutableArray retainCount], [testArray7 retainCount]);
        NSLog(@"testStrongMutableArray NSArray testArray8  copy class:%@ addr:%p, %p,  retainCount:%ld, %ld", [copyTest.testStrongMutableArray class], copyTest.testStrongMutableArray, testArray8, [copyTest.testStrongMutableArray retainCount], [testArray8 retainCount]);
        /*
         2017-02-23 11:30:11.590 test[76507:628350] testCopyArray NSArray testArray5  strong class:__NSSingleObjectArrayI addr:0x600000010cd0, 0x600000010cd0,  retainCount:2, 2
         2017-02-23 11:30:11.591 test[76507:628350] testStrongArray NSArray testArray6  copy class:__NSSingleObjectArrayI addr:0x600000010d20, 0x600000010d20,  retainCount:2, 2
         ///< 下面就会出问题了
         2017-02-23 11:30:11.591 test[76507:628350] testCopyMutableArray NSArray testArray7  copy class:__NSSingleObjectArrayI addr:0x600000010d30, 0x600000010d30,  retainCount:2, 2
         2017-02-23 11:30:11.591 test[76507:628350] testStrongMutableArray NSArray testArray8  copy class:__NSSingleObjectArrayI addr:0x600000010d40, 0x600000010d40,  retainCount:2, 2
         */
    }

block使用copy关键字

方法内:block是在栈区的。使用copy可以把block放到堆区上。
在arc中可以不写。因为对于block使用copy或者strong都是可以的。因为编译器自动对block进行了copy操作。在开发中写上copy关键字 是一个良好的习惯。时刻提醒自己,编译器会对block做copy操作。
在Apple相关文档2 block中也有写:
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.

Apple相关文档1 copy
Apple相关文档2 block

你可能感兴趣的:(从NSCopying协议到copy,mutableCopy)