日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

OC学习篇之---对象的拷贝

發(fā)布時間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OC学习篇之---对象的拷贝 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在前一篇文章中我們說到了如何解決對象的循環(huán)引用問題:http://blog.csdn.net/jiangwei0910410003/article/details/41926369,這一篇文章我們就來介紹一下OC中的對象拷貝概念,這個對于面向?qū)ο笳Z言中都會有這種的問題,只是不同的語言有不同的解決方式:C++中有拷貝構(gòu)造函數(shù),Java中需要實現(xiàn)Cloneable接口,在clone方法中進行操作。但是不過OC更偏向于Java這種方式,OC中如果一個對象需要被拷貝,他需要實現(xiàn)協(xié)議:

<NSCopying><NSMutableCopying>

從名字上我們可以看到,一個協(xié)議是用于不可變對象的,一個協(xié)議適用于可變對象的


首先來介紹一下對象的拷貝的概念吧:

為什么要由對象的拷貝這么一個概念呢?看一個場景:假如現(xiàn)在一個對象中又一個數(shù)組對象,現(xiàn)在我們生成一個對象,同時將這個對象賦值給另外一個對象,那么現(xiàn)在問題是這兩個對象中的數(shù)組對象是同一個,那么如果一個對象中去修改這個數(shù)值中的內(nèi)容,另外一個對象中的數(shù)組內(nèi)容也會被修改,相當于這個數(shù)組對象是共享的,當然我們有時候是不希望這種形式的出現(xiàn)的,這時候我們就出現(xiàn)了對象的拷貝。

具體來看一個例子吧


一、系統(tǒng)類對象的拷貝

//
//  main.m
//  30_CopyObject
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>/***/
int main(int argc, const char * argv[]) {@autoreleasepool {//對象具備拷貝功能,必須實現(xiàn)如下協(xié)議//<NSCopying>、<NSMutableCopying>//copy方法返回的是一個不可變對象,mutableCopy方法返回的是一個可變對象/*NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil];NSMutableArray *array2 = [array1 retain];//retain只是引用計數(shù)+1,沒有創(chuàng)建新的對象//array1與array2指針相同,指向同一個對象if(array1 == array2){NSLog(@"array1 == array2");NSLog(@"array1的引用計數(shù):%ld",array1.retainCount);}*/NSMutableArray *array1 = [NSMutableArray arrayWithObjects:@"one",@"two",nil];//復制對象,創(chuàng)建一個新的副本對象//這里使用copy方法復制,返回的是一個不可變數(shù)組,但是用一個可變數(shù)組來聲明,但是我們關(guān)心的是指針的的內(nèi)容,而不是類型//所以array2的真實類型還是不可變類型的NSMutableArray *array2 = [array1 copy];//array2計數(shù)為:1,因為是新創(chuàng)建出來的對象//使用mutableCopy方法,返回的就是可變數(shù)組//當然這種方法只針對于那些有可變對象之分有用,對于其他的對象這個方法和copy方法的效果是一樣的NSMutableArray *array3 = [array1 mutableCopy];if(array1 != array2){NSLog(@"array1 != array2");NSLog(@"array1的引用計數(shù):%ld",array1.retainCount);NSLog(@"array2的引用計數(shù):%ld",array2.retainCount);}[array2 release];[array1 release];}return 0;
}
我們看到,NSMutableArray有一個mutableCopy方法,這樣返回的一個數(shù)組對象就是一個拷貝對象了。

但是這里需要注意的是:

copy方法和mutableCopy方法的區(qū)別

這兩個方法的區(qū)別只在于那些有可變對象和不可變對象之分的對象上,對于沒有這種區(qū)分的對象來說,這兩個方法的效果是一樣的。

[不可變對象 copy]是假拷貝,等價于[不可變對象 retain]

[不可變對象 mutableCopy是真拷貝



二、深拷貝和淺拷貝

在拷貝對象中也是有深拷貝和淺拷貝之分的

淺拷貝:只拷貝所有屬性對象的指針

深拷貝:拷貝屬性對象的內(nèi)容

看個例子:

Person.h

//
//  Person.h
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>@interface Person : NSObject <NSCopying>@property(nonatomic,retain)NSMutableArray *apples;
@property(nonatomic)int age;@end


Person.m

//
//  Person.m
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import "Person.h"@implementation Person- (id)copyWithZone:(NSZone *)zone{//創(chuàng)建一個新的副本對象//這個方法是會被繼承的,所以這里還是不用//[Person allocWithZone:<#(struct _NSZone *)#>];Person * p = [[self class] allocWithZone:zone];//p.apples = _apples;//是指針賦值,所以還是淺拷貝//深拷貝//拷貝之后引用計數(shù)會+1,需要release以下p.apples = [_apples mutableCopy];p.age = _age;[p.apples release];//但是如果我們使用->語法就不需要了,因為我們沒有使用set方法,引用計數(shù)沒有操作//但是這種方式我們不采用//p->_apples = [_apples mutableCopy];return p;
}@end

我們看到,Person實現(xiàn)了NSCopying協(xié)議,然后需要實現(xiàn)一個方法:copyWithZone

在這個方法中我們開始進行拷貝操作:

Person類中有一個屬性類型是數(shù)組

這里我們需要生成一個Person對象,然后進行屬性的拷貝,最后在返回這個對象

淺拷貝:直接復制數(shù)組指針

深拷貝:直接復制數(shù)組的內(nèi)容,這里可以直接使用mutableCopy方法進行實現(xiàn)


測試類

main.m

//
//  main.m
//  31_DeepCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>
#import "Person.h"//深拷貝和淺拷貝
//默認是淺拷貝
int main(int argc, const char * argv[]) {@autoreleasepool {NSMutableArray *array1 = [NSMutableArray arrayWithCapacity:2];for(int i=0;i<2;i++){Person *p = [[Person alloc] init];[array1 addObject:p];[p release];}//引用計數(shù)都是1for(Person *p in array1){NSLog(@"復制之前的引用計數(shù):%ld",p.retainCount);NSLog(@"復制之前的指針:%p",p);}//引用計數(shù)都是2,因為是淺拷貝,又有指針指向?qū)ο罅?#xff0c;array2也是使用了person//淺拷貝:只拷貝對象指針//深拷貝:復制屬性NSArray *array2 = [array1 copy];for(Person *p in array2){NSLog(@"復制之前的引用計數(shù):%ld",p.retainCount);NSLog(@"復制之前的指針:%p",p);}//這里Person中有一個屬性是NSMutableArray,但是我們只是賦值,并不是拷貝//所以這里還不算是深拷貝Person *p = [[Person alloc] init];p.apples = [NSMutableArray arrayWithObjects:@"iphone",@"ipad", nil];p.age = 20;Person *p1 = [p copy];if(p != p1){NSLog(@"p1.age=%d",p1.age);NSLog(@"p1.apples=%@",p1.apples);}}return 0;
}


三、字符串的拷貝

//
//  main.m
//  32_NSStringCopy
//
//  Created by jiangwei on 14-10-13.
//  Copyright (c) 2014年 jiangwei. All rights reserved.
//#import <Foundation/Foundation.h>#import "Person.h"//字符串為什么使用copy
int main(int argc, const char * argv[]) {@autoreleasepool {Person *p = [[Person alloc] init];NSMutableString *name = [NSMutableString stringWithString:@"jack"];p.name = name;//人的名字被修改了//如果Person的name是retain,則此處的name和person對象的name執(zhí)行的是同一個字符串對象//此處的name修改之后,會導致person的name也被修改,破壞了person對象的封裝性//正常情況下,我們會使用set方法設(shè)置名字//所以如果使用的是copy的話,就不會修改名字了[name appendString:@"-tom"];//Foundation框架中可復制的對象,當我們拷貝的是一個不可變對象時候//他的作用相當于retain(系統(tǒng)做的內(nèi)存優(yōu)化)//所以這里的如果換成NSString類型的時候,其實沒有拷貝的動作的,因為NSString是不可變的//但是使用mutableCopy就可以做到拷貝了,mutableCopy是真正意義上的拷貝//mutableCopy拷貝方法,不管什么對象都是真實拷貝//[不可變對象 copy]是假拷貝,等價于[不可變對象 retain]//[不可變對象 mutableCopy是真拷貝}return 0;
}
這里為什么要單獨說一下字符串的拷貝呢?

因為字符串是一個特殊的對象,我們應該調(diào)用他的copy方法。因為我們對于字符串其實我們是期望他只有一分值得,就看上面的例子:

我們用NSMutableString產(chǎn)生一個name,然后將其賦值給person對象,當我們在外面修改name的內(nèi)容的時候,其實person的name屬性的值也應該修改。所以我們一般在拷貝字符串對象的時候,都會調(diào)用他的copy方法


總結(jié)

這一篇文章主要介紹了OC中對象拷貝的相關(guān)概念和知識點。我們在操作對象的時候,有時候進行拷貝,還要仔細考慮一下是深拷貝還是淺拷貝。




轉(zhuǎn)載于:https://www.cnblogs.com/roccheung/p/5797287.html

總結(jié)

以上是生活随笔為你收集整理的OC学习篇之---对象的拷贝的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。