首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

iOS NSMutableDictionary 添加同一可變數組導致值被覆蓋:引用語義與淺拷貝陷阱

     編輯:程式設計疑難解答

現象代碼

self.arr = [NSMutableArray new];
self.dic = [NSMutableDictionary new];
[self.arr addObjectsFromArray:@[@"1",@"2",@"3"]];
[self.dic setObject:self.arr forKey:@"key1"];

[self.arr removeAllObjects];
[self.arr addObjectsFromArray:@[@"3",@"4",@"5"]];
[self.dic setObject:self.arr forKey:@"key2"];

// 輸出:key1 和 key2 都指向同一個數組對象,內容均為 3,4,5

根因

**字典存儲的是對象引用(指針)**,而非值拷貝。`key1` 和 `key2` 指向同一個 `NSMutableArray` 實例。後續修改數組內容,**兩個鍵觀察到的都是同一份內存**。

修復方案

  1. 每次存入新建不可變副本:
    [self.dic setObject:[self.arr copy] forKey:@"key1"]; // copy 生成 NSArray (不可變)
    [self.arr removeAllObjects];
    [self.arr addObjectsFromArray:@[@"3",@"4",@"5"]];
    [self.dic setObject:[self.arr copy] forKey:@"key2"];
    
  2. 或每次 new 新數組:
    self.arr = [NSMutableArray arrayWithObjects:@"1",@"2",@"3", nil];
    [self.dic setObject:self.arr forKey:@"key1"];
    self.arr = [NSMutableArray arrayWithObjects:@"3",@"4",@"5", nil]; // 重新賦值新對象
    [self.dic setObject:self.arr forKey:@"key2"];
    

深度理解

  • `copy`(協議 `NSCopying`)默認**淺拷貝**:容器類(Array/Dictionary/Set)返回不可變副本,**元素仍共享引用**;自定義類需實現 `copyWithZone:` 決定深/淺。
  • `mutableCopy` 返回可變副本,同樣淺拷貝元素。
  • **集合類只存指針**,這是 Objective-C/Swift 參考語義的核心,**值類型才存值**(Struct/Enum/基本類型)。

最佳實踐

  • **字典/數組作為值存入時,默認用 `copy` 斷開後續修改影響**。
  • 若需共享同一可變集合(如多處觀察同一數據源),**有意識地共享引用**,並用 KVO/通知/Combine 觀察變化。
  • Swift 中 `let arr = [1,2,3]; dict["k"] = arr` 自動值語義複製,**結構體自動深拷貝**,避免此類坑。

理解「引用 vs 值」與「copy 語義」,是 iOS 開發避免數據竄改的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved