retain)| 源對象 | 調用方法 | 結果類型 | 拷貝類型 | 說明 |
|---|---|---|---|---|
| NSString | copy | NSString | 淺 | 不可變→不可變,返回自身,retain+1 |
| NSString | mutableCopy | NSMutableString | 深 | 不可變→可變,必須創建新對象 |
| NSMutableString | copy | NSString | 深 | 可變→不可變,創建不可變副本 |
| NSMutableString | mutableCopy | NSMutableString | 深 | 可變→可變,創建可變副本 |
結論:只有「不可變對象 → copy → 不可變對象」是淺拷貝,其餘均為深拷貝。
// 淺拷貝示例
NSString *str = @"abcd";
NSString *str2 = [str copy];
NSLog(@"str: %p, str2: %p"); // 地址相同
// 深拷貝示例
NSMutableString *mStr = [NSMutableString stringWithString:@"abcd"];
NSString *mStr2 = [mStr copy];
NSLog(@"mStr: %p, mStr2: %p"); // 地址不同
規律完全一致:不可變→copy→不可變 = 淺拷貝;其他組合 = 深拷貝。
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
@interface Person : NSObject
@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithAge:(int)age withName:(NSString *)name;
@end
@implementation Person
- (instancetype)initWithAge:(int)age withName:(NSString *)name {
if (self = [super init]) {
_age = age;
_name = name; // copy 屬性自動複製字符串
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
Person *copy = [[[self class] allocWithZone:zone]
initWithAge:_age withName:_name];
return copy;
}
@end
Person *p1 = [[Person alloc] initWithAge:20 withName:@"Jack"];
Person *p2 = [p1 copy];
NSLog(@"p1: %p, p2: %p"); // 地址不同 → 深拷貝
若對象邏輯上不可變,可直接返回自身:
- (id)copyWithZone:(NSZone *)zone {
return self; // 淺拷貝,等同 NSString 行為
}
子類繼承父類實現的 copyWithZone: 但必須重寫以拷貝自身新增屬性:
@interface Student : Person
@property (nonatomic, copy) NSString *school;
- (instancetype)initWithAge:(int)age withName:(NSString *)name withSchool:(NSString *)school;
@end
@implementation Student
- (instancetype)initWithAge:(int)age withName:(NSString *)name withSchool:(NSString *)school {
if (self = [super initWithAge:age withName:name]) {
_school = school;
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
Student *copy = [super copyWithZone:zone]; // 先調用父類拷貝
copy.school = _school; // 再拷貝自身屬性
return copy;
}
@end
copy:@property (copy) NSString *name; 確保 setter 執行拷貝copy:防止外部修改內部集合NSCopying:自定義模型類必須實現,支持集合拷貝、歸檔等copy/mutableCopy:根據語義選擇,不可變接口返回不可變對象[super copyWithZone:zone] 保證父類屬性正確拷貝copy 一定是深拷貝 → 導致共享可變狀態 BugNSCopying 卻調用 copy → 運行時崩潰copyWithZone: → 新增屬性未拷貝copyWithZone: 中直接賦值指針而非拷貝 → 淺拷貝風險