OC学习篇之---对象的拷贝
<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
// 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)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Unity WWW] 跨域访问解决方法
- 下一篇: Bootstrap学习的点点滴滴