OC中对象拷贝概念
OC中的對象拷貝概念,這個對于面向對象語言中都會有這種的問題,只是不同的語言有不同的解決方式:C++中有拷貝構造函數,Java中需要實現Cloneable接口,在clone方法中進行操作。但是不過OC更偏向于Java這種方式,OC中如果一個對象需要被拷貝,他需要實現協議:
<NSCopying>、<NSMutableCopying>
從名字上我們可以看到,一個協議是用于不可變對象的,一個協議適用于可變對象的
首先來介紹一下對象的拷貝的概念吧:
為什么要由對象的拷貝這么一個概念呢?看一個場景:假如現在一個對象中又一個數組對象,現在我們生成一個對象,同時將這個對象賦值給另外一個對象,那么現在問題是這兩個對象中的數組對象是同一個,那么如果一個對象中去修改這個數值中的內容,另外一個對象中的數組內容也會被修改,相當于這個數組對象是共享的,當然我們有時候是不希望這種形式的出現的,這時候我們就出現了對象的拷貝。
具體來看一個例子吧
一、系統類對象的拷貝
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??30_CopyObject??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. /**?
12. ??
13. ?*/??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ??????????
17. ????????//對象具備拷貝功能,必須實現如下協議??
18. ????????//<NSCopying>、<NSMutableCopying>??
19. ??????????
20. ????????//copy方法返回的是一個不可變對象,mutableCopy方法返回的是一個可變對象??
21. ??????????
22. ????????/*?
23. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithObjects:@"one",@"two",nil];?
24. ????????NSMutableArray?*array2?=?[array1?retain];?
25. ????????//retain只是引用計數+1,沒有創建新的對象?
26. ????????//array1與array2指針相同,指向同一個對象?
27. ????????if(array1?==?array2){?
28. ????????????NSLog(@"array1?==?array2");?
29. ????????????NSLog(@"array1的引用計數:%ld",array1.retainCount);?
30. ????????}?
31. ?????????*/??
32. ??????????
33. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithObjects:@"one",@"two",nil];??
34. ????????//復制對象,創建一個新的副本對象??
35. ????????//這里使用copy方法復制,返回的是一個不可變數組,但是用一個可變數組來聲明,但是我們關心的是指針的的內容,而不是類型??
36. ????????//所以array2的真實類型還是不可變類型的??
37. ????????NSMutableArray?*array2?=?[array1?copy];//array2計數為:1,因為是新創建出來的對象??
38. ??????????
39. ????????//使用mutableCopy方法,返回的就是可變數組??
40. ????????//當然這種方法只針對于那些有可變對象之分有用,對于其他的對象這個方法和copy方法的效果是一樣的??
41. ????????NSMutableArray?*array3?=?[array1?mutableCopy];??
42. ??????????
43. ????????if(array1?!=?array2){??
44. ????????????NSLog(@"array1?!=?array2");??
45. ????????????NSLog(@"array1的引用計數:%ld",array1.retainCount);??
46. ????????????NSLog(@"array2的引用計數:%ld",array2.retainCount);??
47. ????????}??
48. ????????[array2?release];??
49. ????????[array1?release];??
50. ??????????
51. ??????????
52. ????}??
53. ????return?0;??
54. }??
我們看到,NSMutableArray有一個mutableCopy方法,這樣返回的一個數組對象就是一個拷貝對象了。
但是這里需要注意的是:
copy方法和mutableCopy方法的區別
這兩個方法的區別只在于那些有可變對象和不可變對象之分的對象上,對于沒有這種區分的對象來說,這兩個方法的效果是一樣的。
[不可變對象?copy]是假拷貝,等價于[不可變對象?retain]
[不可變對象?mutableCopy是真拷貝
二、深拷貝和淺拷貝
在拷貝對象中也是有深拷貝和淺拷貝之分的
淺拷貝:只拷貝所有屬性對象的指針
深拷貝:拷貝屬性對象的內容
看個例子:
Person.h
[objc]??view plaincopy
1. //??
2. //??Person.h??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. @interface?Person?:?NSObject?<NSCopying>??
12. ??
13. @property(nonatomic,retain)NSMutableArray?*apples;??
14. @property(nonatomic)int?age;??
15. ??
16. @end??
Person.m
[objc]??view plaincopy
1. //??
2. //??Person.m??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?"Person.h"??
10. ??
11. @implementation?Person??
12. ??
13. -?(id)copyWithZone:(NSZone?*)zone{??
14. ????//創建一個新的副本對象??
15. ????//這個方法是會被繼承的,所以這里還是不用??
16. ????//[Person?allocWithZone:<#(struct?_NSZone?*)#>];??
17. ????Person?*?p?=?[[self?class]?allocWithZone:zone];??
18. ????//p.apples?=?_apples;//是指針賦值,所以還是淺拷貝??
19. ????//深拷貝??
20. ????//拷貝之后引用計數會+1,需要release以下??
21. ????p.apples?=?[_apples?mutableCopy];??
22. ????p.age?=?_age;??
23. ??????
24. ????[p.apples?release];??
25. ??????
26. ????//但是如果我們使用->語法就不需要了,因為我們沒有使用set方法,引用計數沒有操作??
27. ????//但是這種方式我們不采用??
28. ????//p->_apples?=?[_apples?mutableCopy];??
29. ??????
30. ????return?p;??
31. }??
32. ??
33. @end??
我們看到,Person實現了NSCopying協議,然后需要實現一個方法:copyWithZone
在這個方法中我們開始進行拷貝操作:
Person類中有一個屬性類型是數組
這里我們需要生成一個Person對象,然后進行屬性的拷貝,最后在返回這個對象
淺拷貝:直接復制數組指針
深拷貝:直接復制數組的內容,這里可以直接使用mutableCopy方法進行實現
測試類
main.m
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. #import?"Person.h"??
11. ??
12. //深拷貝和淺拷貝??
13. //默認是淺拷貝??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ??????????
17. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithCapacity:2];??
18. ??????????
19. ????????for(int?i=0;i<2;i++){??
20. ????????????Person?*p?=?[[Person?alloc]?init];??
21. ????????????[array1?addObject:p];??
22. ????????????[p?release];??
23. ????????}??
24. ??????????
25. ????????//引用計數都是1??
26. ????????for(Person?*p?in?array1){??
27. ????????????NSLog(@"復制之前的引用計數:%ld",p.retainCount);??
28. ????????????NSLog(@"復制之前的指針:%p",p);??
29. ????????}??
30. ??????????
31. ????????//引用計數都是2,因為是淺拷貝,又有指針指向對象了,array2也是使用了person??
32. ????????//淺拷貝:只拷貝對象指針??
33. ????????//深拷貝:復制屬性??
34. ????????NSArray?*array2?=?[array1?copy];??
35. ????????for(Person?*p?in?array2){??
36. ????????????NSLog(@"復制之前的引用計數:%ld",p.retainCount);??
37. ????????????NSLog(@"復制之前的指針:%p",p);??
38. ????????}??
39. ??????????
40. ????????//這里Person中有一個屬性是NSMutableArray,但是我們只是賦值,并不是拷貝??
41. ????????//所以這里還不算是深拷貝??
42. ????????Person?*p?=?[[Person?alloc]?init];??
43. ????????p.apples?=?[NSMutableArray?arrayWithObjects:@"iphone",@"ipad",?nil?nil];??
44. ????????p.age?=?20;??
45. ??????????
46. ????????Person?*p1?=?[p?copy];??
47. ??????????
48. ????????if(p?!=?p1){??
49. ????????????NSLog(@"p1.age=%d",p1.age);??
50. ????????????NSLog(@"p1.apples=%@",p1.apples);??
51. ????????}??
52. ??????????
53. ????}??
54. ????return?0;??
55. }??
三、字符串的拷貝
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??32_NSStringCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. #import?"Person.h"??
12. ??
13. //字符串為什么使用copy??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ????????Person?*p?=?[[Person?alloc]?init];??
17. ????????NSMutableString?*name?=?[NSMutableString?stringWithString:@"jack"];??
18. ????????p.name?=?name;??
19. ??????????
20. ????????//人的名字被修改了??
21. ????????//如果Person的name是retain,則此處的name和person對象的name執行的是同一個字符串對象??
22. ????????//此處的name修改之后,會導致person的name也被修改,破壞了person對象的封裝性??
23. ????????//正常情況下,我們會使用set方法設置名字??
24. ????????//所以如果使用的是copy的話,就不會修改名字了??
25. ????????[name?appendString:@"-tom"];??
26. ??????????
27. ????????//Foundation框架中可復制的對象,當我們拷貝的是一個不可變對象時候??
28. ????????//他的作用相當于retain(系統做的內存優化)??
29. ??????????
30. ????????//所以這里的如果換成NSString類型的時候,其實沒有拷貝的動作的,因為NSString是不可變的??
31. ????????//但是使用mutableCopy就可以做到拷貝了,mutableCopy是真正意義上的拷貝??
32. ????????//mutableCopy拷貝方法,不管什么對象都是真實拷貝??
33. ??????????
34. ????????//[不可變對象?copy]是假拷貝,等價于[不可變對象?retain]??
35. ????????//[不可變對象?mutableCopy是真拷貝??
36. ????}??
37. ????return?0;??
38. }??
這里為什么要單獨說一下字符串的拷貝呢?
因為字符串是一個特殊的對象,我們應該調用他的copy方法。因為我們對于字符串其實我們是期望他只有一分值得,就看上面的例子:
我們用NSMutableString產生一個name,然后將其賦值給person對象,當我們在外面修改name的內容的時候,其實person的name屬性的值也應該修改。所以我們一般在拷貝字符串對象的時候,都會調用他的copy方法
總結 這一篇文章主要介紹了OC中對象拷貝的相關概念和知識點。我們在操作對象的時候,有時候進行拷貝,還要仔細考慮一下是深拷貝還是淺拷貝。
<NSCopying>、<NSMutableCopying>
從名字上我們可以看到,一個協議是用于不可變對象的,一個協議適用于可變對象的
首先來介紹一下對象的拷貝的概念吧:
為什么要由對象的拷貝這么一個概念呢?看一個場景:假如現在一個對象中又一個數組對象,現在我們生成一個對象,同時將這個對象賦值給另外一個對象,那么現在問題是這兩個對象中的數組對象是同一個,那么如果一個對象中去修改這個數值中的內容,另外一個對象中的數組內容也會被修改,相當于這個數組對象是共享的,當然我們有時候是不希望這種形式的出現的,這時候我們就出現了對象的拷貝。
具體來看一個例子吧
一、系統類對象的拷貝
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??30_CopyObject??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. /**?
12. ??
13. ?*/??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ??????????
17. ????????//對象具備拷貝功能,必須實現如下協議??
18. ????????//<NSCopying>、<NSMutableCopying>??
19. ??????????
20. ????????//copy方法返回的是一個不可變對象,mutableCopy方法返回的是一個可變對象??
21. ??????????
22. ????????/*?
23. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithObjects:@"one",@"two",nil];?
24. ????????NSMutableArray?*array2?=?[array1?retain];?
25. ????????//retain只是引用計數+1,沒有創建新的對象?
26. ????????//array1與array2指針相同,指向同一個對象?
27. ????????if(array1?==?array2){?
28. ????????????NSLog(@"array1?==?array2");?
29. ????????????NSLog(@"array1的引用計數:%ld",array1.retainCount);?
30. ????????}?
31. ?????????*/??
32. ??????????
33. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithObjects:@"one",@"two",nil];??
34. ????????//復制對象,創建一個新的副本對象??
35. ????????//這里使用copy方法復制,返回的是一個不可變數組,但是用一個可變數組來聲明,但是我們關心的是指針的的內容,而不是類型??
36. ????????//所以array2的真實類型還是不可變類型的??
37. ????????NSMutableArray?*array2?=?[array1?copy];//array2計數為:1,因為是新創建出來的對象??
38. ??????????
39. ????????//使用mutableCopy方法,返回的就是可變數組??
40. ????????//當然這種方法只針對于那些有可變對象之分有用,對于其他的對象這個方法和copy方法的效果是一樣的??
41. ????????NSMutableArray?*array3?=?[array1?mutableCopy];??
42. ??????????
43. ????????if(array1?!=?array2){??
44. ????????????NSLog(@"array1?!=?array2");??
45. ????????????NSLog(@"array1的引用計數:%ld",array1.retainCount);??
46. ????????????NSLog(@"array2的引用計數:%ld",array2.retainCount);??
47. ????????}??
48. ????????[array2?release];??
49. ????????[array1?release];??
50. ??????????
51. ??????????
52. ????}??
53. ????return?0;??
54. }??
我們看到,NSMutableArray有一個mutableCopy方法,這樣返回的一個數組對象就是一個拷貝對象了。
但是這里需要注意的是:
copy方法和mutableCopy方法的區別
這兩個方法的區別只在于那些有可變對象和不可變對象之分的對象上,對于沒有這種區分的對象來說,這兩個方法的效果是一樣的。
[不可變對象?copy]是假拷貝,等價于[不可變對象?retain]
[不可變對象?mutableCopy是真拷貝
二、深拷貝和淺拷貝
在拷貝對象中也是有深拷貝和淺拷貝之分的
淺拷貝:只拷貝所有屬性對象的指針
深拷貝:拷貝屬性對象的內容
看個例子:
Person.h
[objc]??view plaincopy
1. //??
2. //??Person.h??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. @interface?Person?:?NSObject?<NSCopying>??
12. ??
13. @property(nonatomic,retain)NSMutableArray?*apples;??
14. @property(nonatomic)int?age;??
15. ??
16. @end??
Person.m
[objc]??view plaincopy
1. //??
2. //??Person.m??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?"Person.h"??
10. ??
11. @implementation?Person??
12. ??
13. -?(id)copyWithZone:(NSZone?*)zone{??
14. ????//創建一個新的副本對象??
15. ????//這個方法是會被繼承的,所以這里還是不用??
16. ????//[Person?allocWithZone:<#(struct?_NSZone?*)#>];??
17. ????Person?*?p?=?[[self?class]?allocWithZone:zone];??
18. ????//p.apples?=?_apples;//是指針賦值,所以還是淺拷貝??
19. ????//深拷貝??
20. ????//拷貝之后引用計數會+1,需要release以下??
21. ????p.apples?=?[_apples?mutableCopy];??
22. ????p.age?=?_age;??
23. ??????
24. ????[p.apples?release];??
25. ??????
26. ????//但是如果我們使用->語法就不需要了,因為我們沒有使用set方法,引用計數沒有操作??
27. ????//但是這種方式我們不采用??
28. ????//p->_apples?=?[_apples?mutableCopy];??
29. ??????
30. ????return?p;??
31. }??
32. ??
33. @end??
我們看到,Person實現了NSCopying協議,然后需要實現一個方法:copyWithZone
在這個方法中我們開始進行拷貝操作:
Person類中有一個屬性類型是數組
這里我們需要生成一個Person對象,然后進行屬性的拷貝,最后在返回這個對象
淺拷貝:直接復制數組指針
深拷貝:直接復制數組的內容,這里可以直接使用mutableCopy方法進行實現
測試類
main.m
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??31_DeepCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. #import?"Person.h"??
11. ??
12. //深拷貝和淺拷貝??
13. //默認是淺拷貝??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ??????????
17. ????????NSMutableArray?*array1?=?[NSMutableArray?arrayWithCapacity:2];??
18. ??????????
19. ????????for(int?i=0;i<2;i++){??
20. ????????????Person?*p?=?[[Person?alloc]?init];??
21. ????????????[array1?addObject:p];??
22. ????????????[p?release];??
23. ????????}??
24. ??????????
25. ????????//引用計數都是1??
26. ????????for(Person?*p?in?array1){??
27. ????????????NSLog(@"復制之前的引用計數:%ld",p.retainCount);??
28. ????????????NSLog(@"復制之前的指針:%p",p);??
29. ????????}??
30. ??????????
31. ????????//引用計數都是2,因為是淺拷貝,又有指針指向對象了,array2也是使用了person??
32. ????????//淺拷貝:只拷貝對象指針??
33. ????????//深拷貝:復制屬性??
34. ????????NSArray?*array2?=?[array1?copy];??
35. ????????for(Person?*p?in?array2){??
36. ????????????NSLog(@"復制之前的引用計數:%ld",p.retainCount);??
37. ????????????NSLog(@"復制之前的指針:%p",p);??
38. ????????}??
39. ??????????
40. ????????//這里Person中有一個屬性是NSMutableArray,但是我們只是賦值,并不是拷貝??
41. ????????//所以這里還不算是深拷貝??
42. ????????Person?*p?=?[[Person?alloc]?init];??
43. ????????p.apples?=?[NSMutableArray?arrayWithObjects:@"iphone",@"ipad",?nil?nil];??
44. ????????p.age?=?20;??
45. ??????????
46. ????????Person?*p1?=?[p?copy];??
47. ??????????
48. ????????if(p?!=?p1){??
49. ????????????NSLog(@"p1.age=%d",p1.age);??
50. ????????????NSLog(@"p1.apples=%@",p1.apples);??
51. ????????}??
52. ??????????
53. ????}??
54. ????return?0;??
55. }??
三、字符串的拷貝
[objc]??view plaincopy
1. //??
2. //??main.m??
3. //??32_NSStringCopy??
4. //??
5. //??Created?by?jiangwei?on?14-10-13.??
6. //??Copyright?(c)?2014年?jiangwei.?All?rights?reserved.??
7. //??
8. ??
9. #import?<Foundation/Foundation.h>??
10. ??
11. #import?"Person.h"??
12. ??
13. //字符串為什么使用copy??
14. int?main(int?argc,?const?charchar?*?argv[])?{??
15. ????@autoreleasepool?{??
16. ????????Person?*p?=?[[Person?alloc]?init];??
17. ????????NSMutableString?*name?=?[NSMutableString?stringWithString:@"jack"];??
18. ????????p.name?=?name;??
19. ??????????
20. ????????//人的名字被修改了??
21. ????????//如果Person的name是retain,則此處的name和person對象的name執行的是同一個字符串對象??
22. ????????//此處的name修改之后,會導致person的name也被修改,破壞了person對象的封裝性??
23. ????????//正常情況下,我們會使用set方法設置名字??
24. ????????//所以如果使用的是copy的話,就不會修改名字了??
25. ????????[name?appendString:@"-tom"];??
26. ??????????
27. ????????//Foundation框架中可復制的對象,當我們拷貝的是一個不可變對象時候??
28. ????????//他的作用相當于retain(系統做的內存優化)??
29. ??????????
30. ????????//所以這里的如果換成NSString類型的時候,其實沒有拷貝的動作的,因為NSString是不可變的??
31. ????????//但是使用mutableCopy就可以做到拷貝了,mutableCopy是真正意義上的拷貝??
32. ????????//mutableCopy拷貝方法,不管什么對象都是真實拷貝??
33. ??????????
34. ????????//[不可變對象?copy]是假拷貝,等價于[不可變對象?retain]??
35. ????????//[不可變對象?mutableCopy是真拷貝??
36. ????}??
37. ????return?0;??
38. }??
這里為什么要單獨說一下字符串的拷貝呢?
因為字符串是一個特殊的對象,我們應該調用他的copy方法。因為我們對于字符串其實我們是期望他只有一分值得,就看上面的例子:
我們用NSMutableString產生一個name,然后將其賦值給person對象,當我們在外面修改name的內容的時候,其實person的name屬性的值也應該修改。所以我們一般在拷貝字符串對象的時候,都會調用他的copy方法
總結 這一篇文章主要介紹了OC中對象拷貝的相關概念和知識點。我們在操作對象的時候,有時候進行拷貝,還要仔細考慮一下是深拷貝還是淺拷貝。
轉載于:https://www.cnblogs.com/GhostKZShadow/p/5105220.html
總結
- 上一篇: 1.3.3 改善后的异常处理
- 下一篇: 常用的数组的操作