iOS - OC Copy 拷貝

前言

  • copy:需要先實現 NSCopying 協議,創建的是不可變副本。

  • mutableCopy:需要實現 NSMutableCopying 協議,創建的是可變副本。

  • 淺拷貝:指針拷貝,源對象和副本指向的是同一個對象。對象的引用計數器 +1,其實相當于做了一次 retain 操作。

  • 深拷貝:內容拷貝,源對象和副本指向的是兩個不同的對象。源對象引用計數器不變,副本計數器設置為 1。

  • 只有不可變對象創建不可變副本(copy)才是淺拷貝,其它都是深拷貝。

  • 在 iOS 中并不是所有的對象都支持 copy,mutableCopy,遵守 NSCopying 協議的類可以發送 copy 消息,遵守 NSMutableCopying 協議的類才可以發送 mutableCopy 消息。假如發送了一個沒有遵守上 訴兩協議而發送 copy 或者 mutableCopy,那么就會發生異常。但是默認的 iOS 類并沒有遵守這兩個協議。如果想自定義一下 copy 那么就必須遵守 NSCopying,并且實現 copyWithZone: 方法,如果想自定義一下 mutableCopy 那么就必須遵守 NSMutableCopying,并且實現 mutableCopyWithZone: 方法。

  • copy 是創建一個新對象,retain 是創建一個指針,引用對象計數加 1。copy 屬性表示兩個對象內容相同,新的對象 retain 為 1 ,與舊有對象的引用計數無關,舊有對象沒有變化。copy 減少對象對上下文的依賴。retain 屬性表示兩個對象地址相同(建立一個指針,指針拷貝),內容當然相同,這個對象的 retain 值 +1 也就是說,retain 是指針拷貝,copy 是內容拷貝。

1、系統的非容器類對象

    /*系統的非容器類對象指的是 NSString,NSNumber 等等一類的對象。對于系統的非容器類對象,如果對一不可變對象復制,copy 是指針復制(淺拷貝),mutableCopy 就是對象復制(深拷貝)。如果是對可變對象復制,都是深拷貝,但是 copy 返回的對象是不可變的。*/NSString *string = @"origion";NSString *stringCopy = [string copy];NSMutableString *mstringMCopy = [string mutableCopy];NSLog(@"%p", string);NSLog(@"%p", stringCopy);                       // 地址與 string 相同NSLog(@"%p", mstringMCopy);                     // 地址與 string 不同NSLog(@"%zi", [string retainCount]);            // 引用計數為 2NSLog(@"%zi", [stringCopy retainCount]);        // 引用計數為 2NSLog(@"%zi", [mstringMCopy retainCount]);      // 引用計數為 1NSLog(@"%@", stringCopy);                       // 內容與 string 相同NSLog(@"%@", mstringMCopy);                     // 內容與 string 相同[mstringMCopy appendString:@"!!"];              // mstringMCopy 是可變的NSLog(@"%@", mstringMCopy);/*string 和 stringCopy 指向的是同一塊內存區域(又叫 apple 弱引用 weak reference),此時 stringCopy 的引用計數和 string 的一樣都為2。而 mstringMCopy 則是我們所說的真正意義上的復制,系統為其分配了新內存,但指針所指向的字符串還是和 string 所指的一樣。*/NSMutableString *mstring = [NSMutableString stringWithString: @"origion"];NSString *stringCopy = [mstring copy];NSMutableString *mStringCopy = [mstring copy];NSMutableString *mstringMCopy = [mstring mutableCopy];NSLog(@"%p", mstring);NSLog(@"%p", stringCopy);                       // 地址與 string 不同NSLog(@"%p", mStringCopy);                      // 地址與 string 不同,與 stringCopy 相同NSLog(@"%p", mstringMCopy);                     // 地址與 string 不同NSLog(@"%@", mstring);NSLog(@"%@", stringCopy);                       // 內容與 string 相同NSLog(@"%@", mStringCopy);                      // 內容與 string 相同NSLog(@"%@", mstringMCopy);                     // 內容與 string 相同[mstring appendString:@" origion!"];// [mStringCopy appendString:@"mm"];            // error,mStringCopy 不可變[mstringMCopy appendString:@"!!"];              // mstringMCopy 可變NSLog(@"%@", mstring);NSLog(@"%@", mstringMCopy);/* 以上四個 NSString 對象所分配的內存都是不一樣的。但是對于 mStringCopy 其實是個不可變對象,所以上述會報錯。*/

2、系統的容器類對象

    /*系統的容器類對象指 NSArray,NSDictionary 等。對于容器類本身,上面討論的結論也是適用的,需要探討的是復制后容器內對象的變化。對于系統的容器類對象,copy 返回不可變對象,是指針復制,包括里面的元素也是指向相同的指針。mutablecopy 返回可變對象,是對象復制,其中容器內的元素內容都是指針復制,可以改變其內的元素。*/NSArray *array = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];NSArray *arrayCopy = [array copy];NSMutableArray *mArrayMCopy = [array mutableCopy];NSLog(@"%p", array);NSLog(@"%p", arrayCopy);                        // 地址與 array 相同NSLog(@"%p", mArrayMCopy);                      // 地址與 array 不同NSLog(@"%zi",[array retainCount]);NSLog(@"%zi",[arrayCopy retainCount]);NSLog(@"%zi",[mArrayMCopy retainCount]);NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 內容與 array 相同NSLog(@"%@", mArrayMCopy);                      // 內容與 array 相同[mArrayMCopy addObject:@"de"];                  // mArrayMCopy 可變NSLog(@"%@", array);NSLog(@"%@", mArrayMCopy);[mArrayMCopy removeObjectAtIndex:0];NSLog(@"%@", array);NSLog(@"%@", mArrayMCopy);/*copy 返回不可變對象,mutablecopy 返回可變對象,arrayCopy 是指針復制,而 mArrayMCopy 是對象復制。arrayCopy 是和 array 同一個 NSArray 對象(指向相同的對象),包括 array 里面的元素也是指向相同的指針。mArrayMCopy 是 array 的可變副本,指向的對象和 array 不同,但是其中的元素和 array 中的元素指向的是同一個對象。mArrayMCopy 還可以改變其內的元素:刪除或添加。但是注意的是,容器內的元素內容都是指針復制。*/NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"a"], @"b", @"c", nil];NSArray *arrayCopy = [array copy];NSMutableArray *mArrayMCopy = [array mutableCopy];NSLog(@"%p", array);NSLog(@"%p", arrayCopy);                        // 地址與 array 相同NSLog(@"%p", mArrayMCopy);                      // 地址與 array 不同NSLog(@"%zi",[array retainCount]);NSLog(@"%zi",[arrayCopy retainCount]);NSLog(@"%zi",[mArrayMCopy retainCount]);NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 內容與 array 相同NSLog(@"%@", mArrayMCopy);                      // 內容與 array 相同NSMutableString *testString = [array objectAtIndex:0];[testString setString:@"1a1"];                  // 這樣會改變 testString 的指針,其實是將 @“1a1” 臨時對象賦給了 testString。這樣以上三個數組的首元素都被改變了。NSLog(@"%@", array);NSLog(@"%@", arrayCopy);                        // 內容與 array 相同NSLog(@"%@", mArrayMCopy);                      // 內容與 array 相同/*arrayCopy,mArrayMCopy 和 array 指向的都是不一樣的對象,但是其中的元素都是一樣的對象,同一個指針。對于容器而言,其元素對象始終是指針復制。如果需要元素對象也是對象復制,就需要實現深拷貝。*/NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"first"], @"b", @"c", nil];NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array copyItems: YES];// 使用歸檔/反歸檔拷貝NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject: array]];   NSLog(@"%@", array);NSLog(@"%@", deepCopyArray);                    // 內容與 array 相同NSLog(@"%@", trueDeepCopyArray);                // 內容與 array 相同NSMutableString *testString1 = [array objectAtIndex:0];[testString1 setString:@"1a1"];NSLog(@"%@", array);NSLog(@"%@", deepCopyArray);                    // 內容與 array 不同NSLog(@"%@", trueDeepCopyArray);                // 內容與 array 不同/*trueDeepCopyArray 是完全意義上的深拷貝,而 deepCopyArray 則不是,對于 deepCopyArray 內的不可變元素其還是指針復制。或者我們自己實現深拷貝的方法。因為如果容器的某一元素是不可變的,那你復制完后該對象仍舊是不能改變的,因此只需要指針復制即可。除非你對容器內的元素重新賦值,否則指針復制即已足夠。舉個例子,[[array objectAtIndex:0] appendstring:@”sd”] 后其他的容器內對象并不會受影響。[[array objectAtIndex:1] 和 [[deepCopyArray objectAtIndex:1] 盡管是指向同一塊內存,但是我們沒有辦法對其進行修改——因為它是不可改變的。所以指針復制已經足夠。所以這并不是完全意義上的深拷貝,但是 apple 的官方文檔將其列為 deep copy 了,并添加了 copy 和 mutablity 的關系說明。*/

3、自定義對象

  • 需要自己要實現 NSCopying,NSMutableCopying 這樣就能調用 copy 和 mutablecopy 了。
    // Teacher.h// 遵守 NSCopying, NSMutableCopying 協議@interface Teacher : NSObject <NSCopying, NSMutableCopying>@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) int age;@end// Teacher.m@implementation Teacher// 實現協議方法,委托方會自動調用協議中的該方法- (id)copyWithZone:(NSZone *)zone{Teacher *copy = [[Teacher allocWithZone:zone] init];copy.name = self.name;copy.age = self.age;return copy;}// 實現協議方法,委托方會自動調用協議中的該方法- (id)mutableCopyWithZone:(NSZone *)zone{Teacher *copy = [[Teacher allocWithZone:zone] init];          copy.name = self.name;copy.age = self.age;return copy;}- (NSString *)description{return [NSString stringWithFormat:@"%@  %i", self.name, self.age];}@end// main.m#import "Teacher.h"Teacher *tch = [[Teacher alloc] init];tch.name = @"xiao xin";tch.age = 28;// 內容復制Teacher *tchCpy = [tch copy];// 內容復制Teacher *tchMCopy = [tch mutableCopy];tchCpy.age = 20;tchMCopy.age = 22;NSLog(@"%p", tch);// tchCpy 與 tch 的地址不同NSLog(@"%p", tchCpy);// tchMCopy 與 tch 的地址不同NSLog(@"%p", tchMCopy);NSLog(@"%@", tch);// tchCpy 與 tch 的實例變量的值不同NSLog(@"%@", tchCpy);// tchMCopy 與 tch 的實例變量的值不同NSLog(@"%@", tchMCopy);// Children.h// 遵守 NSCopying, NSMutableCopying 協議@interface Children : NSObject <NSCopying, NSMutableCopying>@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) int age;@end// Children.m@implementation Children// 實現協議方法,委托方會自動調用協議中的該方法。- (id)copyWithZone:(NSZone *)zone{// 若有類繼承此類,并且此方法在子類中可用id copy = [[[self class] allocWithZone:zone] init];[copy setName:self.name];[copy setAge:self.age];return copy;}// 實現協議方法,委托方會自動調用協議中的該方法。- (id)mutableCopyWithZone:(NSZone *)zone{// 若有類繼承此類,并且此方法在子類中可用id copy = [[[self class] allocWithZone:zone] init];[copy setName:self.name];[copy setAge:self.age];return copy;}@end// GoodChildren.h@interface GoodChildren : Children@property (nonatomic, assign)int score;@end// GoodChildren.m@implementation GoodChildren// 實現協議方法,委托方會自動調用協議中的該方法。- (id)copyWithZone:(NSZone *)zone{                                      GoodChildren *copy = [super copyWithZone:zone];copy.score = self.score;return copy;}// 實現協議方法,委托方會自動調用協議中的該方法。- (id)mutableCopyWithZone:(NSZone *)zone{                               GoodChildren *copy = [super copyWithZone:zone];copy.score = self.score;return copy;}- (NSString *)description{return [NSString stringWithFormat:@"%@  %i  %d", self.name, self.age, self.score];}@end// main.m#import "GoodChildren.h"GoodChildren *gChild = [[GoodChildren alloc] init];gChild.name = @"xiao xin";gChild.age = 18;gChild.score = 88;// 內容復制GoodChildren *gChildCopy = [gChild copy];// 內容復制GoodChildren *gChildMCopy = [gChild mutableCopy];gChildCopy.age = 20;gChildMCopy.age = 22;gChildCopy.score = 100;gChildMCopy.score = 120;NSLog(@"%p", gChild);// gChildCopy 與 gChild 的地址不同NSLog(@"%p", gChildCopy);// gChildMCopy 與 gChild 的地址不同NSLog(@"%p", gChildMCopy);NSLog(@"%@", gChild);// gChildCopy 與 gChild 的實例變量的值不同NSLog(@"%@", gChildCopy);// gChildMCopy 與 gChild 的實例變量的值不同NSLog(@"%@", gChildMCopy);

轉載于:https://www.cnblogs.com/QianChia/p/5782887.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/283970.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/283970.shtml
英文地址,請注明出處:http://en.pswp.cn/news/283970.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

三.選擇結構(一)

1.if結構: if(條件){ 代碼塊 } 2.隨機產生數: int randon (int)(Math.random()*10); 3.多重if選擇結構: if(條件1){ 代碼塊1 }else if (條件2){ 代碼塊2 }else{ 代碼塊3 } 4.嵌套if選擇結構: if(條件1){ if(條件2){ 代碼塊1 }else{ 代碼塊2 } }else{ 代碼塊3 } 轉載于:https://…

為了高性能、超大規模的模型訓練,這個組合“出道”了

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;3分鐘)近年來&#xff0c;在大量數據上訓練的基于 transformer 的大規模深度學習模型在多項認知任務中取得了很好的成果&#xff0c;并且被使用到一些新產品和功能背后&#xff0c;進一步增強了人類的能力。在過去五年…

SVN就是這么簡單

什么是SVN SVN全稱&#xff1a;Subversion&#xff0c;是一個開放源代碼的版本控制系統 Svn是一種集中式文件版本管理系統。集中式代碼管理的核心是服務器&#xff0c;所有開發者在開始新一天的工作之前必須從服務器獲取代碼&#xff0c;然后開發&#xff0c;最后解決沖突&…

SpringCloud必會知識點大全

為什么要學習Spring Cloud 在項目開發中隨著業務越來越多&#xff0c;導致功能之間耦合性高、開發效率低、系統運行緩慢難以維護、不穩定。微服務 架構可以解決這些問題&#xff0c;而Spring Cloud是微服務架構最流行的實現. 1.微服務 微服務架構是使用一套小服務來開發單個應用…

thinkphp3.22 多項目配置

1.index.php if(version_compare(PHP_VERSION,5.3.0,<)) die(require PHP > 5.3.0 !); // 開啟調試模式 建議開發階段開啟 部署階段注釋或者設為false define(APP_DEBUG,true); // 創建 //define(BIND_MODULE,Login); define(erp,true); // 定義應用目錄 define(APP_PAT…

30分鐘掌握 C#7

1. out 變量&#xff08;out variables&#xff09; 以前我們使用out變量必須在使用前進行聲明&#xff0c;C# 7.0 給我們提供了一種更簡潔的語法 “使用時進行內聯聲明” 。如下所示&#xff1a; 1 var input ReadLine(); 2 if (int.TryParse(input, out var result)) 3 …

在 C# 中如何檢查參數是否為 null

前言前不久&#xff0c;微軟宣布從 C# 11 中移除參數空值檢查功能&#xff0c;該功能允許在方法開始執行之前&#xff0c;在參數名稱的末尾提供參數空值檢查&#xff08;!!操作符&#xff09;。那么&#xff0c;在 C# 中如何檢查參數是否為 null 呢&#xff1f;1. null這個可能…

什么是Maven快照(SNAPSHOT)

本文來說下Maven的SNAPSHOT版本有什么作用 文章目錄 問題解決 正式版本"abc-1.0"快照版本"abc-1.0-SNAPSHOT"本文小結問題 在使用maven進行依賴管理時&#xff0c;有的版本號后面會帶有"-SNAPSHOT"&#xff0c;有什么作用呢&#xff1f; <dep…

帶你剖析WebGis的世界奧秘----Geojson數據加載(高級)

前言&#xff1a;前兩周我帶你們分析了WebGis中關鍵步驟瓦片加載點擊事件&#xff08;具體的看前兩篇文章&#xff09;&#xff0c;下面呢&#xff0c;我帶大家來看看Geojson的加載及其點擊事件 Geojson數據解析 GeoJSON是一種對各種地理數據結構進行編碼的格式。GeoJSON對象可…

如果要存ip地址,用什么數據類型比較好

在看高性能MySQL第3版&#xff08;4.1.7節&#xff09;時&#xff0c;作者建議當存儲IPv4地址時&#xff0c;應該使用32位的無符號整數&#xff08;UNSIGNED INT&#xff09;來存儲IP地址&#xff0c;而不是使用字符串。但是沒有給出具體原因。為了搞清楚這個原因&#xff0c;查…

微軟 .NET Core 3.1 年底將結束支持,請升級到.NET 6

微軟近日宣布&#xff0c;將于 2022 年 12 月 13 日停止為 .NET Core 3.1 提供服務更新、安全修復和技術支持。.NET Core 是一個免費開源的、用于 Windows、Linux 和 macOS 操作系統的軟件框架。該項目主要由微軟員工通過 .NET 基金會開發&#xff0c;并在 MIT 許可下發布。202…

軟件團隊的模式選擇

軟件團隊的模式分為&#xff1a;主治醫生模式、明星模式、社區模式、業余劇團模式、秘密團隊、特工團隊、交響樂團模式、爵士樂模式、功能團隊模式和官僚模式。 經過小組的討論&#xff0c;我們決定選用交響樂團模式獲得功能團隊模式。 交響樂團模式的優點是種類多&#xff0c;…

Angular 2

1. Angular2 官網 https://angular.io/guide/quickstart Node.js 下載 https://nodejs.org/en/ 怎么在vs code中使用angualr2 https://code.visualstudio.com/docs/nodejs/angular-tutorial moment.js:(javacript日期處理庫) http://momentjs.cn/ 2. ng2-hightCharts https://…

「Docker入門指北」容器很難理解?帶你從頭到尾捋一遍

文章目錄 1. 初始虛擬化 &#x1f351; 虛擬化概念&#x1f351; 硬件虛擬化2. Docker容器 &#x1f351; Docker技術的誕生&#x1f351; 容器與虛擬化&#x1f351; 性能差別&#x1f351; Docker優勢 編排有序高效易遷移快速部署3. 容器生態系統 &#x1f351; 核心技術 容器…

微服務:事務管理

幾乎所有的信息管理系統都會涉及到事務&#xff0c;事務的目的是為了保證數據的一致性&#xff0c;這里說的一致性是數據庫狀態的一致性。說到數據庫狀態的一致性&#xff0c;相信大家都會想到 ACID &#xff1a;原子性&#xff08;Atomic&#xff09;&#xff1a;在一個事件的…

js - flex布局測試案例:完美居中

<span>I love flex layout!</span><style>body{display:flex;justify-content:center;align-items:center;font-size:3em;color:#00ffff;}</style>![enter image description here][1]<p>與自己為敵&#xff0c;</p><p>與自己為友&a…

操作數據庫(對戰小游戲)

創建數據庫 1 create database duizhan2 go3 use duizhan4 go5 create table duizhan6 (7 Code varchar(20) not null primary key,8 Name varchar(20) not null,9 Sex varchar(20) not null, 10 Blood int, 11 Attack int, 12 Defence int, 13 Mingzhong…

8-Python3從入門到實戰—基礎之數據類型(集合-Sets)

Python從入門到實戰系列——目錄 集合的定義 集合&#xff08;set&#xff09;和字典類似&#xff0c;也是一組key的集合&#xff0c;但不存儲value&#xff1b;由于key不能重復&#xff0c;所以&#xff0c;在set中&#xff0c;沒有重復的key。創建一個set&#xff0c;需要提供…

Redis的那些事:一文入門Redis的基礎操作

Redis是什么Redis&#xff0c;全稱是Remote Dictionary Service,翻譯過來就是&#xff0c;遠程字典服務。redis屬于nosql非關系型數據庫。Nosql常見的數據關系&#xff0c;基本上是以key-value鍵值對形式存在的。Key-value: 就像翻閱中文字典或者單詞字典&#xff0c;通過指定的…

10種提問型爆文標題句式 直接套用

如果你用1天的時間來寫篇好文章&#xff0c;那你花掉半天時間想一個好標題都不過分&#xff01; 你是不是覺得我有點言過其實了&#xff1f;沒關系&#xff0c;先來問你2個問題&#xff1a; 1、花了很長時間&#xff0c;寫了一篇很牛的賣貨推文&#xff0c;定稿后&#xff0c…