從NSCopying協(xié)議到copy,mutableCopy

NSCopying 對應(yīng)copy

想要使某個類支持拷貝功能牙勘,返回不可變對象论泛,只需要將這個類遵從NSCopying協(xié)議并實(shí)現(xiàn)其中的方法即可(只有一個方法)揩尸。

///< NSZone:之前再開發(fā)程序的時候,會據(jù)此把內(nèi)存分成不同的“區(qū)”(zone)屁奏,而對象會創(chuàng)建在某個區(qū)里面岩榆。
///< 現(xiàn)在每個程序只有一個區(qū)“默認(rèn)區(qū)(default zone)”,所以盡管必須實(shí)現(xiàn)這個方法坟瓢,但是不必?fù)?dān)心zone參數(shù)勇边。
- (id)copyWithZone:(nullable NSZone *)zone;


當(dāng)我們實(shí)現(xiàn)了NSCopying協(xié)議后,通過類對象調(diào)用copy方法時折联,copy方法會去調(diào)用copyWithZone方法粒褒。
注意:Foundation框架中的所有collection類在默認(rèn)情況下都執(zhí)行的是淺拷貝。

@interface A : NSObject <NSCopying>

@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]诚镰,因?yàn)橹羔樋赡軐?shí)際指向的是A的子類奕坟。
    A *copyA = [[[self class] allocWithZone:zone] initWithName:_name];
    return copyA;
}

@end

NSMutableCopying 對應(yīng)mutableCopy

與NSCopying協(xié)議類似,此協(xié)議對應(yīng)可變對象清笨。

- (id)mutableCopyWithZone:(nullable NSZone *)zone;
無論當(dāng)前版本是否可變月杉,如果需要獲取其可變版本的拷貝,均應(yīng)調(diào)用mutableCopy方法抠艾。若要獲取不可變版本的拷貝苛萎,需要通過copy方法獲取。
[NSMutableArray copy]  => NSArray
[NSArray mutableCopy]  => NSMutableArray

*** 注意:*** 如果自定義對象分為可變版本和不可變版本检号,那么需要同時實(shí)現(xiàn)NSCopying和NSMutableCopying協(xié)議腌歉。

在C++中有一種構(gòu)造函數(shù)叫:copy構(gòu)造函數(shù)喲。

copy與mutableCopy一個實(shí)例

{
        ///< 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
         */
    }
image.png

深copy 與 淺copy

深copy:當(dāng)一個類擁有資源齐苛,當(dāng)這個類的對象(資源)發(fā)生復(fù)制的過程翘盖。(copy完后的對象與被copy對象相互獨(dú)立,不會相互影響)
淺copy:復(fù)制過程中并未復(fù)制資源的情況脸狸。

property 中的copy(內(nèi)存語意)

先release舊值最仑,再copy新值藐俺。復(fù)制一個對象并創(chuàng)建strong關(guān)聯(lián)炊甲。copy的本質(zhì)為復(fù)制該內(nèi)存所存儲的內(nèi)容,重新創(chuàng)建一個對象賦給其相同的內(nèi)容欲芹。
通俗點(diǎn):copy一個新對象卿啡,新對象引用計(jì)數(shù)+1,原對象不變菱父。

在NSString颈娜,NSArray剑逃,NSDictionary等 經(jīng)常使用copy關(guān)鍵字,why官辽?(這個問題被說爛了吧)

由于他們都對應(yīng)有Mutable版本蛹磺。
在實(shí)際使用時,父類的指針可以指向?qū)?yīng)子類的對象同仆,我們使用copy的牧師是為了讓本對象的屬性不受外界影響萤捆,使用copy無論給我傳入的是一個可變對象還是不可變對象,我本身持有的就是一個不可變的副本俗批。
如果我們使用strong俗或,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改岁忘,那么會影響該屬性值辛慰。
相關(guān)測試:

{
        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關(guān)鍵字

方法內(nèi):block是在棧區(qū)的。使用copy可以把block放到堆區(qū)上干像。
在arc中可以不寫帅腌。因?yàn)閷τ赽lock使用copy或者strong都是可以的。因?yàn)榫幾g器自動對block進(jìn)行了copy操作蝠筑。在開發(fā)中寫上copy關(guān)鍵字 是一個良好的習(xí)慣狞膘。時刻提醒自己,編譯器會對block做copy操作什乙。
Apple相關(guān)文檔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相關(guān)文檔1 copy
Apple相關(guān)文檔2 block

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挽封,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子臣镣,更是在濱河造成了極大的恐慌辅愿,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忆某,死亡現(xiàn)場離奇詭異点待,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)弃舒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門癞埠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人聋呢,你說我怎么就攤上這事苗踪。” “怎么了削锰?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵通铲,是天一觀的道長。 經(jīng)常有香客問我器贩,道長颅夺,這世上最難降的妖魔是什么朋截? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮吧黄,結(jié)果婚禮上部服,老公的妹妹穿的比我還像新娘。我一直安慰自己拗慨,他們只是感情好饲宿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胆描,像睡著了一般瘫想。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昌讲,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天国夜,我揣著相機(jī)與錄音,去河邊找鬼短绸。 笑死车吹,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的醋闭。 我是一名探鬼主播窄驹,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼证逻!你這毒婦竟也來了乐埠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤囚企,失蹤者是張志新(化名)和其女友劉穎丈咐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體龙宏,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棵逊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了银酗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辆影。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖黍特,靈堂內(nèi)的尸體忽然破棺而出蛙讥,到底是詐尸還是另有隱情,我是刑警寧澤衅澈,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布键菱,位于F島的核電站谬墙,受9級特大地震影響今布,放射性物質(zhì)發(fā)生泄漏经备。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一部默、第九天 我趴在偏房一處隱蔽的房頂上張望侵蒙。 院中可真熱鬧,春花似錦傅蹂、人聲如沸纷闺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽犁功。三九已至,卻和暖如春婚夫,著一層夾襖步出監(jiān)牢的瞬間浸卦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工案糙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留限嫌,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓时捌,卻偏偏與公主長得像怒医,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奢讨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容