1.簡單復制只能實現淺拷貝:指針賦值,使兩個指針指向相同的一塊內存空間,操作不安全。
2. Foundation類已經遵守了<NSCopying>和 <NSMutableCopying>協議,即實現了copy和mutableCopy方法,因此Foundation對象可以使用這些方法創建對象的副本或可變副本
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
3.用戶自定義類遵守<NSCopying>協議和<NSMutableCopying>協議,則必須實現copyWithZone方法和mutableCopyWithZone方法,否則該類對象無法響應copy和mutableCopy消息?
4.實現copyWithZone方法,例:
? ? ? ?
-(id)copyWithZone:(NSZone *)zone
{
???????? Student *stu = [[Student?allocWithZone:zone]initWithName:self.name?Age:self.age];
???????? return stu;
}
對應main函數中:假設已經有一個Student對象stu1;
則:Student stu2 = [stu1 copy];
實現stu2是stu1的副本,這里是深復制,stu1和stu2分別對應不同內存。
?
5. 如果你的類產生了子類,那么copyWithZone:方法也將
被繼承
Student *stu = [[Student allocWithZone: zone] init];
?該方法應該改為: Student *stu =?[[[self class]?allocWithZone: zone]init];
?如果編寫一個類的copyWithZone:方法那么子類的方法應該先調用父類的copy方法以復制繼承來的copy實例變量.
1 NSCopying與NSMutableCopying協議
用copy方法能得到字符串的不可變副本,而mutableCopy方法能得到字符串的可變副本。?但是如果對自定義的類,我們不能直接使用copy和mutableCopy方法,需要讓類遵守NSCopying與NSMutableCopying協議,然后實現繼承自協議的copyWithZone:方法和mutableCopyWithZone:方法,這兩個方法返回的是對象本身,得到一個對象的副本。
總之,為了保證一個自定義的類的對象使用copy方法產生一個不可變的副本,需要做兩步:?
1. 讓該類繼承NSCopying協議。?
2. 在類的代碼實現部分重寫繼承自NSCopying協議的CopyWithZone:方法,該方法返回一個該類的不可變對象副本。
為了保證一個自定義的類的對象使用mutableCopy方法產生一個可變的副本,需要做兩步:?
1. 讓該類繼承NSMutableCopying協議。?
2. 在類的代碼實現部分重寫繼承自NSMutableCopying協議的mutableCopyWithZone:方法,該方法返回一個該類的可變對象副本。
2 深復制和淺復制
代碼示例如下:?GKHUser.h
[code]#import <Foundation/Foundation.h>//繼承NSCopying和NSMutableCopying協議 @interface GKHUser : NSObject <NSCopying, NSMutableCopying> @property (nonatomic, strong) NSMutableString *name;//類似retain類型,引用計數 @property (nonatomic, assign) int age; @end
GKHUser.m
[code]#import "GKHUser.h"@implementation GKHUser//重寫copyWithZone:方法 - (id) copyWithZone:(NSZone *)zone {NSLog(@"執行copyWithZone:方法");//使用zone參數創建一個GKHUser對象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = self.name;//這里只是淺復制user.age = self.age;return user; }//重寫mutableCopyWithZone:方法 - (id) mutableCopyWithZone:(NSZone *)zone {NSLog(@"執行mutableCopyWithZone:方法");//使用zone參數創建一個GKHUser對象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = self.name;//這里只是淺復制user.age = self.age;return user; } @end
main.m
[code]#import <Foundation/Foundation.h> #import "GKHUser.h"int main(int argc, const char * argv[]) {@autoreleasepool {GKHUser *user1 = [GKHUser new];user1.name = [NSMutableString stringWithString:@"李太"];user1.age = 10;GKHUser *user2 = [user1 copy];//復制不可變副本[user1.name appendString:@"白"];user2.age = 20;NSLog(@"user1的名字為:%@", user1.name);NSLog(@"user1的年齡為:%d", user1.age);NSLog(@"user2的名字為:%@", user2.name);NSLog(@"user2的年齡為:%d", user2.age);GKHUser *user3 = [GKHUser new];user3.name = [NSMutableString stringWithString:@"張大"];user3.age = 30;GKHUser *user4 = [user3 mutableCopy];//復制可變副本[user3.name appendString:@"彪"];user4.age = 40;NSLog(@"user3的名字為:%@", user3.name);NSLog(@"user3的年齡為:%d", user3.age);NSLog(@"user4的名字為:%@", user4.name);NSLog(@"user4的年齡為:%d", user4.age);}return 0; }
運行main.m結果:
執行copyWithZone:方法?
user1的名字為:李太白?
user1的年齡為:10?
user2的名字為:李太白?
user2的年齡為:20?
執行mutableCopyWithZone:方法?
user3的名字為:張大彪?
user3的年齡為:30?
user4的名字為:張大彪?
user4的年齡為:40
我們從結果中發現,不管是可變復制還是不可變復制,最后修改副本的name屬性時候,會導致原始對象的屬性也發生修改,為什么呢?因為這里的copyWithZone:和mutableWithZone:方法中對name屬性的賦值是淺復制,如下圖:

為了達到我們的效果,GKHUser.h和main.m代碼不變,而GKHUser.m修改如下:?
GKHUser.m
[code]#import "GKHUser.h"@implementation GKHUser//重寫copyWithZone:方法 - (id) copyWithZone:(NSZone *)zone {NSLog(@"執行copyWithZone:方法");//使用zone參數創建一個GKHUser對象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = [self.name copy];//這里對name指向的對象執行深復制,復制的副本為不可變的字符串user.age = self.age;return user; }//重寫mutableCopyWithZone:方法 - (id) mutableCopyWithZone:(NSZone *)zone {NSLog(@"執行mutableCopyWithZone:方法");//使用zone參數創建一個GKHUser對象GKHUser *user = [[[self class] allocWithZone:zone] init];user.name = [self.name mutableCopy];//這里對name指向的對象執行深復制,復制的副本為可變的字符串user.age = self.age;return user; } @end
運行main.m結果:
執行copyWithZone:方法?
user1的名字為:李太白?
user1的年齡為:10?
user2的名字為:李太?
user2的年齡為:20?
執行mutableCopyWithZone:方法?
user3的名字為:張大彪?
user3的年齡為:30?
user4的名字為:張大?
user4的年齡為:40
這樣就達到了我們的目的,user2是user1的不可變副本,實現了copy方法,而user4是user3的可變副本,實現了mutableCopy方法。?
其在內存中的示意圖如下:
