IOS開發複製的總結(深拷貝淺拷貝區別)
1.複製可變字串
NSMutableString * city = [NSMutableString stringWithString:@"北京"]; //複製可變副本 NSMutableString * cityCopy = [city mutableCopy]; //修改副本 [cityCopy replaceCharactersInRange:NSMakeRange(0, 2) withString:@"臨滄"]; //輸出看到原字串沒有改變 當前的改變 NSLog(@"原來的city是%@,現在的cityCopy是%@",city,cityCopy);
2.複製不可變字串的可變副本
NSString * str =@"測試的字串"; NSMutableString * strCopy = [str mutableCopy]; //增加字串 [strCopy appendString:@"再加一段字串"]; NSLog(@"strCopy是是%@",strCopy); //為可變字串返回一個不可變副本 NSMutableString * cityCopy2 = [city copy]; //由於city是不可變的下面的代碼是錯誤的 [cityCopy2 appendString:@"這樣是錯的"];
報錯資訊
// 2015-05-05 17:19:37.988 copyDemo[424:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendString:'
// *** First throw call stack:
總結 複製的時候返回的字串是否可變與原來的字串或是複製時給予的類型沒有關係。主要取決於調用了copy方法還是mutableCopy方法。
3.對象拷貝
對於自訂的對象我們需要實現NSCopying和NSMutableCopying
@interface Person : NSObject@property(nonatomic,strong)NSMutableString *name;@property(nonatomic,assign)int age;@end
#import "Person.h"@interface Person()@end@implementation Person- (id)copyWithZone:(NSZone *)zone{ Person * person = [[[self class] allocWithZone:zone] init]; person.name = self.name; person.age = self.age; return person;}@end
#import #import "Person.h"int main(int argc, const char * argv[]) { @autoreleasepool { Person * person = [Person new]; person.name = [NSMutableString stringWithString:@"小明"]; person.age = 20; Person * personCopy = [person copy];//複製副本 personCopy.name = [NSMutableString stringWithString:@"小強"]; personCopy.age =23; NSLog(@"person的名字是%@",person.name); NSLog(@"person的n年齡是%d",person.age); NSLog(@"personCopy的名字是%@",personCopy.name); NSLog(@"personCopy的年齡是%d",personCopy.age);// 2015-05-05 17:38:43.980 copyDemo[531:303] person的名字是小明// 2015-05-05 17:38:43.981 copyDemo[531:303] person的n年齡是20// 2015-05-05 17:38:43.981 copyDemo[531:303] personCopy的名字是小強// 2015-05-05 17:38:43.982 copyDemo[531:303] personCopy的年齡是23 } return 0;}
4.淺拷貝
其他不變修改main函數
Person * person = [Person new]; person.name = [NSMutableString stringWithString:@"小明"]; person.age = 20; Person * personCopy = [person copy];//複製副本 [personCopy.name replaceCharactersInRange:NSMakeRange(0,2) withString:@"變了嘛"]; personCopy.age =23; NSLog(@"person的名字是%@",person.name); NSLog(@"person的n年齡是%d",person.age); NSLog(@"personCopy的名字是%@",personCopy.name); NSLog(@"personCopy的年齡是%d",personCopy.age);
列印出來的是
2015-05-05 17:54:05.347 copyDemo[563:303] person的名字是變了嘛
2015-05-05 17:54:05.349 copyDemo[563:303] person的n年齡是20
2015-05-05 17:54:05.350 copyDemo[563:303] personCopy的名字是變了嘛
2015-05-05 17:54:05.350 copyDemo[563:303] personCopy的年齡是23
一開始我也很迷惑。差距只有一句代碼而已。不過還是有差別的。
原因就在
person.name = self.name; person.age = self.age;
name是一個指標變數,存放的只是字串地而已。所以說修改了拷貝的name,原來的name也會發生改變,使用personCopy.name = [NSMutableString stringWithString:@"小強"];這句代碼的話其實是直接重新賦值,指向了另外一個字串指標,所以拷貝的對象修改了。原來的並沒有改變。但是並不代表拷貝的時候不指向一個字串。只是後來被修改了。
5.深拷貝
將copyWithZone方法裡面的修改
person.name = [self.name mutableCopy]; person.age = self.age;
這樣就實現了深複製。
但是一般情況下,深複製難度比較大。尤其是有很多指標的時候,Fundation一般都是淺複製。
6.setetr方法的複製
修改如下代碼
@property(nonatomic,copy)NSMutableString *name;
修改main
Person * person = [Person new]; person.name = [NSMutableString stringWithString:@"小明"]; //下面這行代碼會報錯的。 [person.name appendString:@"會報錯了"];
name的屬性使用了copy指示符的話其實相當於setNmame方法裡面
- (void)setName(NSString *)name{name = [name copy];}
是對參數的一個不可變拷貝