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

Objective-C 循環引用詳解:Dog 與 Person 的糾纏與解耦

     編輯:關於C語言

Objective-C 循環引用詳解:Dog 與 Person 的糾纏與解耦

循環引用是手動引用計數(MRC)時代最常見的內存洩漏來源。當兩個對象互相 強引用(retain)對方時,釋放任一對象都無法將計數降至零,導致 dealloc 永不調用,內存永不回收。

問題代碼

// Dog.h
@property (nonatomic, assign, readwrite) Person *person; // 關鍵:assign 不 retain

// Dog.m
- (void)dealloc { NSLog(@"dog dealloc"); [super dealloc]; }

// Person.h
@property (nonatomic, retain, readwrite) Dog *dog; // 強引用

// Person.m
- (void)dealloc { [_dog release]; NSLog(@"Person dealloc"); [super dealloc]; }

// main.m
Person *p = [[Person alloc] init];   // p 計數=1
Dog *dog = [[Dog alloc] init];       // dog 計數=1
[p setDog:dog];   // dog 計數=2
[dog setPerson:p]; // p 計數=2
[p release];      // p 計數=1
[dog release];    // dog 計數=1
// 此時雙方計數均為1,dealloc 未執行,互相等待 → 洩漏
NSLog(@"is over"); // 程序結束前對象未釋放

根因分析

  • Person retain Dog,Dog retain Person(若 Dog 屬性用 retain)。
  • 外部釋放後,雙方計數均為 1,dealloc 不被調用,內部 release 代碼不執行,形成死鎖。

解決方案:單向弱引用

  • 在「被動」一方(通常是子對象、代理、回調持有者)使用 assign(MRC)或 weak(ARC)。
  • 示例中 Dog.person 定義為 assign,不增加 Person 計數。
  • Dog.dealloc 中不調用 [_person release]。

最佳實踐原則

  1. 父擁有子,強引用(retain/strong)。
  2. 子引用父,弱引用(assign/weak)。
  3. 代理/回調,弱引用。
  4. 交叉引用,一方強一方弱。

ARC 時代的對應

  • assign → weak(自動置 nil)或 unsafe_unretained(不置 nil)。
  • 編譯器會強制檢查 weak 修飾的屬性在對象銷毀時自動清零,更安全。

循環引用本質是所有權邏輯混淆。明確「誰擁有誰」,在非擁有方使用弱引用,是解決之道。

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