IOS ObjectiveC中的賦值與對(duì)象拷貝
IOS ObjectiveC中的賦值與對(duì)象拷貝
在開發(fā)過程中我們經(jīng)常會(huì)遇到對(duì)象拷貝的問題,下面我們分別討論賦值操作、對(duì)象拷貝、以及淺拷貝(Shallow copy)與深拷貝(Deep copy)的區(qū)別與各自的實(shí)現(xiàn)方式。
一、不同對(duì)象的賦值操作
Objective-C中有兩類對(duì)象,一類是結(jié)構(gòu)體(或者基本數(shù)據(jù)類型也算),另一類是NSObject對(duì)象。
對(duì)于結(jié)構(gòu)體,代碼直接會(huì)操作其實(shí)體,因此賦值操作會(huì)創(chuàng)建一個(gè)源對(duì)象的副本(一個(gè)新的對(duì)象);而對(duì)于NSObject對(duì)象,必須使用指針來操作對(duì)象,所以其賦值操作相當(dāng)于復(fù)制了指針,而非對(duì)象,也就是說賦值操作使得源指針和新指針都指向同一個(gè)NSObject對(duì)象。這樣講有些難以理解,請(qǐng)看下面的代碼:
// main.m #import <Foundation/Foundation.h> @interface TestObject : NSObject { @public int x; int y; } @end @implementation TestObject @end typedef struct TestStruct { int x; int y; } TestStruct; int main(int argc, const char * argv[]) { @autoreleasepool { TestStruct ts1 = {100, 50}; NSLog(@"ts1: %p, %d, %d", &ts1, ts1.x, ts1.y); TestStruct ts2 = ts1; NSLog(@"ts2: %p, %d, %d", &ts2, ts2.x, ts2.y); TestObject* to1 = [[[TestObject alloc] init] autorelease]; NSLog(@"to1: %p, %d, %d", to1, to1->x, to1->y); TestObject* to2 = to1; NSLog(@"to2: %p, %d, %d", to2, to2->x, to2->y); } return 0; }
程序的運(yùn)行結(jié)果如下:
ts1: 0x7fff63463898, 100, 50 ts2: 0x7fff63463890, 100, 50 to1: 0x7fc342d00370, 0, 0 to2: 0x7fc342d00370, 0, 0
程序代碼首先定義了一個(gè)類TestObject(繼承自NSObject),然后又定義了一個(gè)結(jié)構(gòu)體TestStruct。這兩者都包含兩個(gè)整型的成員變量x和y。然后在main函數(shù)中,程序首先為TestStruct結(jié)構(gòu)體ts1分配內(nèi)存空間,并為其成員變量賦初值,x為100,y為50。然后通過NSLog函數(shù)打印出該結(jié)構(gòu)體的地址和成員變量的值,即輸出的第一行內(nèi)容。接著,程序執(zhí)行了賦值語句,將ts1賦值給另一個(gè)TestStruct結(jié)構(gòu)體對(duì)象ts2,這條語句會(huì)為ts2分配另一塊內(nèi)存,然后把ts1的每個(gè)成員變量的值復(fù)制過來。第二行輸出也可以看出來,地址不一樣了,所以如果修改ts1的成員變量的值,是不會(huì)影響ts2的。
接著再來看TestObject。程序接著使用alloc靜態(tài)方法分配了一塊新的內(nèi)存空間,然后通過init實(shí)例方法進(jìn)行初始化(所有成員變量的值為0),最后將該內(nèi)存空間的首地址返回。to1的實(shí)質(zhì)就是一個(gè)指針,指向創(chuàng)建的TestObject對(duì)象。接著,程序?qū)o1賦值給to2。to2也是一個(gè)指向TestObject對(duì)象的指針,其值與to1一樣,即兩者都指向同一個(gè)對(duì)象。所以在這種情況下,對(duì)to1的修改會(huì)同時(shí)影響to2。
二、對(duì)象拷貝
Foundation框架的NSObject類提供了兩個(gè)方法,分別是copy和mutableCopy方法,用于對(duì)NSObject對(duì)象進(jìn)行拷貝操作。copy方法會(huì)調(diào)用NSCopying協(xié)議的copyWithZone:方法,而mutableCopy會(huì)調(diào)用 NSMutableCopying協(xié)議的mutableCopyWithZone:方法。將上面的代碼修改如下:
#import <Foundation/Foundation.h> @interface TestObject : NSObject { @public int x; int y; } @end @implementation TestObject - (NSString*)description { return [NSString stringWithFormat:@"%@: %p, x: %d, y: %d", [self class], self, x, y]; } @end typedef struct TestStruct { int x; int y; } TestStruct; int main(int argc, const char * argv[]) { @autoreleasepool { TestObject* to1 = [[[TestObject alloc] init] autorelease]; to1->x = 100; to1->y = 50; TestObject* to2 = [[[TestObject alloc] init] autorelease]; to2->x = 200; to2->y = 400; TestObject* to3 = [[[TestObject alloc] init] autorelease]; to3->x = 300; to3->y = 500; //創(chuàng)建包含to1, to2, to3的數(shù)組array1 NSArray* array1 = [NSArray arrayWithObjects:to1, to2, to3, nil]; NSLog(@"array1: %p, \n%@", array1, array1); //array2是array1調(diào)用copy的結(jié)果 NSArray* array2 = [array1 copy]; NSLog(@"array2: %p, \n%@", array2, array2); [array2 release]; //mutableArray2是array1調(diào)用mutableCopy的結(jié)果 NSMutableArray* mutableArray2 = [array1 mutableCopy]; NSLog(@"mutableArray2: %@, %p, \n%@", [mutableArray2 class], mutableArray2, mutableArray2); [mutableArray2 removeLastObject]; NSLog(@"After remove last object of mutableArray2"); NSLog(@"array1: %p, \n%@", array1, array1); NSLog(@"array2: %p, \n%@", array2, array2); NSLog(@"mutableArray2: %p, \n%@", mutableArray2, mutableArray2); //mutableArray3是mutableArray2調(diào)用mutableCopy的結(jié)果 NSMutableArray* mutableArray3 = [mutableArray2 mutableCopy]; NSLog(@"mutableArray3: %p, \n%@", mutableArray3, mutableArray3); [mutableArray2 release]; //array4是mutableArray3調(diào)用copy的結(jié)果 NSArray* array4 = [mutableArray3 copy]; NSLog(@"array4: %@, %p, \n%@", [array4 class], array4, array4); [mutableArray3 release]; [array4 release]; } return 0; }
程序的運(yùn)行結(jié)果如下:
2012-03-22 19:20:49.548 ObjectCopy[18042:403] array1: 0x7f9071414820, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400", "TestObject: 0x7f9071414230, x: 300, y: 500" ) 2012-03-22 19:20:49.550 ObjectCopy[18042:403] array2: 0x7f9071414820, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400", "TestObject: 0x7f9071414230, x: 300, y: 500" ) 2012-03-22 19:20:49.551 ObjectCopy[18042:403] mutableArray2: __NSArrayM, 0x7f9072800000, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400", "TestObject: 0x7f9071414230, x: 300, y: 500" ) 2012-03-22 19:20:49.552 ObjectCopy[18042:403] After remove last object of mutableArray2 2012-03-22 19:20:49.552 ObjectCopy[18042:403] array1: 0x7f9071414820, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400", "TestObject: 0x7f9071414230, x: 300, y: 500" ) 2012-03-22 19:20:49.553 ObjectCopy[18042:403] array2: 0x7f9071414820, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400", "TestObject: 0x7f9071414230, x: 300, y: 500" ) 2012-03-22 19:20:49.553 ObjectCopy[18042:403] mutableArray2: 0x7f9072800000, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400" ) 2012-03-22 19:20:49.557 ObjectCopy[18042:403] mutableArray3: 0x7f90729000d0, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400" ) 2012-03-22 19:20:49.558 ObjectCopy[18042:403] array4: __NSArrayI, 0x7f9071416e70, ( "TestObject: 0x7f90714141b0, x: 100, y: 50", "TestObject: 0x7f90714141c0, x: 200, y: 400" )
程序的運(yùn)行結(jié)果有幾點(diǎn)值得注意,首先是array1與array2的地址相同,因?yàn)镹SArray對(duì)象在創(chuàng)建之后是不可以修改的。其次,NSArray的mutableCopy方法會(huì)返回一個(gè)NSMutableArray對(duì)象。第三,對(duì)于NSArray或者NSMutableArray來說,mutableCopy方法會(huì)創(chuàng)建新的可變數(shù)組對(duì)象,但其每個(gè)數(shù)組成員的值僅僅是原數(shù)組的一個(gè)指針賦值,這就是淺拷貝。而與之相對(duì)的則是深拷貝,即復(fù)制數(shù)組時(shí)不是復(fù)制數(shù)組每個(gè)元素的引用,而是創(chuàng)建一個(gè)與之相同的新對(duì)象。
第四,在NSArray對(duì)象上調(diào)用mutableCopy方法返回一個(gè)NSMutableArray對(duì)象,而在NSMutableArray對(duì)象上調(diào)用copy方法則返回一個(gè)NSArray對(duì)象,而不是NSMutableArray對(duì)象。
當(dāng)然,以上討論的是Foundation框架中的NSArray與NSMutableArray類,如果想要實(shí)現(xiàn)對(duì)自己創(chuàng)建的類的對(duì)象進(jìn)行拷貝,則需要讓類實(shí)現(xiàn)NSCopying協(xié)議。
如有疑問請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
iOS框架AVFoundation實(shí)現(xiàn)相機(jī)拍照、錄制視頻
這篇文章主要為大家詳細(xì)介紹了iOS框架AVFoundation實(shí)現(xiàn)相機(jī)拍照、錄制視頻功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05xcode8提交ipa失敗無法構(gòu)建版本問題的解決方案
xcode升級(jí)到xcode8后發(fā)現(xiàn)構(gòu)建不了新的版本。怎么解決呢?下面小編給大家?guī)砹藊code8提交ipa失敗無法構(gòu)建版本問題的解決方案,非常不錯(cuò),一起看看吧2016-10-10iOS中的UIKeyboard鍵盤視圖使用方法小結(jié)
鍵盤視圖我們平時(shí)在做App的時(shí)候都要調(diào)用得到,這里我們就來整理一下iOS中的UIKeyboard鍵盤視圖使用方法小結(jié),需要的朋友可以參考下2016-06-06iOS App設(shè)計(jì)模式開發(fā)之適配器模式使用的實(shí)戰(zhàn)演練
這篇文章主要介紹了iOS App設(shè)計(jì)模式開發(fā)之適配器模式的使用實(shí)例,示例代碼為傳統(tǒng)的Objective-C語言,需要的朋友可以參考下2016-03-03iOS利用CoreImage實(shí)現(xiàn)人臉識(shí)別詳解
OS的人臉識(shí)別從iOS 5(2011)就有了,不過一直沒怎么被關(guān)注過。人臉識(shí)別API允許開發(fā)者不僅可以檢測(cè)人臉,也可以檢測(cè)到面部的一些特殊屬性,比如說微笑或眨眼。下面這篇文章主要給大家介紹了iOS利用CoreImage實(shí)現(xiàn)人臉識(shí)別的相關(guān)資料,需要的朋友可以參考下。2017-05-05iOS13適配三指撤銷和文案限長(zhǎng)實(shí)例詳解
這篇文章主要為大家介紹了iOS13適配三指撤銷和文案限長(zhǎng)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01