概述
- 拷貝:復制一個與源對象內容相同的對象
- 實現拷貝,需要遵守以下兩個協議
- NSCopying
- NSMutableCopying
- 拷貝返回對象的種類
- 可變,mutableCopy消息返回的對象
- 不可變,copy消息返回的對象
- 拷貝的種類
- 淺拷貝,只是復制了一個指向源對象的指針,未創建對象,未分配內存
- 深拷貝,復制了源對象,創建了新對象,分配了內存
- 注意
- 系統對容器類的對象與非容器類的對象的內存處理是不同的,即當一個沒有被其他對象強引用的對象從容器中移除后,該對象就銷毀
Copy與Retain
- copy
- 是創建一個新的對象,內容拷貝
- copy表示的是兩個對象的內容相同, 新對象的引用計數為1
- 與舊對象的引用計數無關,就對象沒有變化
- copy減少了對象對上下文的
- retain
- 創建的是一個指針,指針拷貝
- 對象地址相同,內容固然相同
- 對象的引用計數+1
不同對象的拷貝行為
-
非容器對象(
如NSString
))- 對於不可變對象
-
規則
- copy,淺拷貝(指針復制)
- mutableCopy,深拷貝(對象復制),返回對象可變(產生新的 可變對象)
-
示例
- (void)imutableInstanceCopy { NSString *string = @"Welcome to Xcode"; //copy,淺拷貝 NSString *stringCopy = [string copy]; //mutableCopy,返回的對象可變 NSMutableString *stringMutableCopy = [string mutableCopy]; [stringMutableCopy appendString:@"!"]; //string與stringCopy的內存地址相同 NSLog(@"string: %p", string); NSLog(@"strongCopy: %p", stringCopy); //string與stringMutableCopy的內存地址不同,分配了新的內存 NSLog(@"stringMCopy:%p", stringMutableCopy); }
-
- 對於可變對象
-
規則
- copy,深拷貝(對象復制),返回對象不可變
- mutableCopy,深拷貝(對象復制)
-
示例
- (void)mutableInstanceCopy { NSMutableString *mutableString = [NSMutableString stringWithString: @"Welcome to Xcode"]; //深拷貝,返回對象不可變 NSString *stringCopy = [mutableString copy]; NSMutableString *mutableStringCopy = [mutableString copy]; //運行時,此句會報錯,錯誤信息“Attempt to mutate immutable object with appendString:” [mutableStringCopy appendString:@"~~~"]; //深拷貝,返回對象可變 NSMutableString *stringMutableCopy = [mutableString mutableCopy]; [stringMutableCopy appendString:@"!"]; //三者與mutableString的內存地址都不同 NSLog(@"mutableString: %p", mutableString); NSLog(@"string: %p", stringCopy); NSLog(@"mutableStringCopy: %p", mutableStringCopy); NSLog(@"stringMutbleCopy:%p", stringMutableCopy); }
-
- 對於不可變對象
-
容器對象(
NSArray
)-
遵循非容器對象的拷貝原則
-
注意
-
容器內的元素是指針賦值(淺拷貝)
-
示例
- (void)containerInstanceShallowCopy { NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil]; //淺拷貝 NSArray *arrayCopy = [array copy]; //深拷貝 NSMutableArray *arrayMutableCopy = [array mutableCopy]; NSLog(@"array: %p", array); NSLog(@"arrayCopy: %p", arrayCopy); NSLog(@"arrayMutableCopy: %p", arrayMutableCopy); //容器內的對象是淺拷貝,即它們在內存中只有一份 NSMutableString *testString = [array objectAtIndex:0]; [testString appendString:@" you"]; //三個數組的內容同時改變 NSLog(@"array[0]: %@", array[0]); NSLog(@"arrayCopy[0]: %@", arrayCopy[0]); NSLog(@"arrayMutableCopy[0]: %@", arrayMutableCopy[0]); }
-
-
實現真正意義上的深復制
- (void)containerInstanceDeepCopy { NSArray *array = [NSArray arrayWithObjects:[NSMutableString stringWithString:@"Welcome"],@"to",@"Xcode",nil]; //數組內對象是指針復制 NSArray *deepCopyArray = [[NSArray alloc] initWithArray:array]; //真正以上的深復制,數組內對象是對象復制 NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array]]; NSLog(@"array: %p", array); NSLog(@"deepCopyArray: %p", deepCopyArray); NSLog(@"trueDeepCopyArray: %p", trueDeepCopyArray); //改變array的第一個元素 [[array objectAtIndex:0] appendString:@" you"]; //只影響deepCopyArray數組的第一個元素 NSLog(@"array[0]: %@", array[0]); NSLog(@"arrayCopy[0]: %@", deepCopyArray[0]); //不影響trueDeepCopyArray數組的第一個元素,是真正意義上的深拷貝 NSLog(@"arrayMutableCopy[0]: %@", trueDeepCopyArray[0]); }
-
-
自定義對象
- 在定義對象要實現拷貝,需要遵守NSCoping與NSMutableCoping協議,並實現以下方法
- - (id)copyWithZone:(NSZone *)zone,可變拷貝
- - (id)mutableCopyWithZone:(NSZone *)zone,不可變拷貝
- 示例(自定對象Person的拷貝)
-
遵守協議,設置成員屬性
@interface Person : NSObject <NSCopying, NSMutableCopying> /**姓名*/ @property (nonatomic, copy) NSMutableString *name; /**地址*/ @property (nonatomic, copy) NSString *address; /**年齡*/ @property (nonatomic, assign) NSInteger age; @end
-
重寫初始化方法
- (instancetype)init { if (self = [super init]) { self.name = [[NSMutableString alloc] initWithString:@"XiaoYaowang"]; self.address = @"世俗孤島"; self.age = 3; } return self; }
-
實現- (id)copyWithZone:(NSZone *)zone
- (id)copyWithZone:(NSZone *)zone { Person *p = [[[self class] allocWithZone:zone] init]; p.name = [self.name copy]; p.address = [self.address copy]; p.age = self.age; return p; }
-
實現- (id)mutableCopyWithZone:(NSZone *)zone
- (id)mutableCopyWithZone:(NSZone *)zone { Person *p = [[[self class] allocWithZone:zone] init]; //注意,此處是mutableCopy方法 p.name = [self.name mutableCopy]; p.address = [self.address copy]; p.age = self.age; return p; }
-
- 在定義對象要實現拷貝,需要遵守NSCoping與NSMutableCoping協議,並實現以下方法