首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C copy 與 mutableCopy 深度解析:協議、淺拷貝、深拷貝與存檔實現

     編輯:關於C語言

核心前提:並非所有物件都支援 copy

  • copy:要求類別遵守 NSCopying 協議,實現 copyWithZone:
  • mutableCopy:要求類別遵守 NSMutableCopying 協議,實現 mutableCopyWithZone:
  • NSObject 預設不遵守這兩個協議,直接調用會拋出異常
  • 基礎類別 NSString、NSNumber、NSArray、NSDictionary 等均遵守 NSCopying

複製語義區別

原物件 retainCount 不變,無需釋放原物件。

自定義類別實現 NSCopying (淺拷貝)


@interface BankAccount : NSObject  {
    double accountBalance;
    long accountNumber;
}
- (void)setAccount:(long)number andBalance:(double)balance;
- (id)copyWithZone:(NSZone *)zone;
@end

@implementation BankAccount
- (id)copyWithZone:(NSZone *)zone {
    BankAccount *copy = [[[self class] allocWithZone:zone] init];
    [copy setAccount:accountNumber andBalance:accountBalance];
    return copy;
}
@end

淺拷貝特徵:僅複製指標值,指向同一記憶體區塊。修改其中一個物件的屬性(如 NSMutableString*),另一個也會受影響。

深拷貝:利用歸檔/解檔實現真正獨立


NSArray *myArray1 = @[@"Red", @"Green", @"Blue"]; // 含可變物件

// 歸檔 -> 序列化為 NSData
NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject:myArray1];

// 解檔 -> 反序列化為新物件圖
NSArray *myArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:buffer];

// 驗證獨立性
NSMutableString *str1 = myArray1[0];
[str1 setString:@"Yellow"]; // 修改原陣列元素

NSLog(@"myArray1[0]: %@", myArray1[0]); // Yellow
NSLog(@"myArray2[0]: %@", myArray2[0]); // Red (未受影響)

原理:NSKeyedArchiver 遞歸編碼整個物件圖,NSKeyedUnarchiver 重建全新物件樹,實現完全深拷貝。要求所有涉及類別實現 NSCoding 協議 (encodeWithCoder:, initWithCoder:)。

屬性修飾符與 copy 的協作


@property (copy) NSString *name;        // setter 內部調用 [newValue copy]
@property (copy) NSArray *items;        // 確保內部持有不可變快照
@property (strong) NSMutableArray *mutableItems; // 內部需可變時用 strong
  • copy 修飾符適用於有可變對應類別的不可變類別 (NSString/NSArray/NSDictionary/NSIndexSet...)
  • 自定義類別若想支援 @property(copy),必須實現 copyWithZone:

實戰陷阱與最佳實踐

  1. 集合類別的 copy 是單層淺拷貝:[array copy] 新陣列元素仍指向舊物件。需深拷貝請用歸檔或手動遞歸複製。
  2. 不可變類別的 copy 優化:[NSString copy] 通常返回 self (retain),不分配新記憶體,效能極高。
  3. MRC 環境記憶體管理:
    
    NSString *copy = [original copy]; // retainCount +1
    [copy release]; // 用完必須釋放
    
  4. ARC 環境:編譯器自動插入 retain/release,但語義不變。

總結決策樹

需要複製物件?
├─ 是不可變類別 (NSString, NSArray...) → 直接 copy (極快,可能是 retain)
├─ 需要可變副本 → mutableCopy
├─ 自定義類別 → 實現 NSCopying (淺拷貝) 或 NSCoding + 歸檔 (深拷貝)
└─ 集合類別深拷貝 → NSKeyedArchiver/Unarchiver (需所有元素支援 NSCoding)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法返回物件可變性記憶體管理
copy新物件不可變調用者負責 release (MRC) / 持有 (ARC)
mutableCopy新物件可變同 copy