Objective-C中,類的例項變數(instance variables)和屬性(properties)是兩種不同的概念,其中屬性的記憶體管理就較為複雜。Objective-C 提供了多種屬性修飾符,用於管理物件的記憶體。這些修飾符用於控制物件的生命週期和記憶體管理行為。
以下是一些常見的屬性修飾符及其記憶體管理行為的詳細介紹:
1. strong
- 適用物件:通常用於物件型別(如
NSObject
及其子類)。 - 記憶體管理:
strong
屬性會對物件進行強引用計數。當一個物件被賦值給一個strong
屬性時,該物件的引用計數會增加 1。當這個屬性被設定為nil
或物件被釋放時,引用計數會減少 1。 - 生命週期:只要有一個
strong
引用指向物件,該物件就不會被釋放。
示例
@property (nonatomic, strong) NSString *name;
在這個示例中,name
屬性是一個 strong
引用,這意味著只要 name
屬性指向的物件存在,引用計數就會增加,確保物件不會被釋放。
2. weak
- 適用物件:通常用於物件型別,特別是在避免迴圈引用時。
- 記憶體管理:
weak
屬性不會對物件進行強引用計數。當物件被釋放時,weak
屬性會自動設定為nil
,避免懸掛指標問題。 - 生命週期:
weak
引用不會延長物件的生命週期。
示例
@property (nonatomic, weak) id<SomeDelegate> delegate;
在這個示例中,delegate
屬性是一個 weak
引用,這意味著當 delegate
物件被釋放時,delegate
屬性會自動設定為 nil
。
3. assign
- 適用物件:通常用於基本資料型別(如
int
、float
、BOOL
)和非物件型別(如NSInteger
、CGFloat
)。 - 記憶體管理:
assign
屬性不會對物件進行引用計數管理。它只是簡單地賦值,不會增加或減少引用計數。 - 生命週期:如果
assign
屬性指向一個物件,當該物件被釋放時,assign
屬性不會自動設定為nil
,可能會導致懸掛指標(dangling pointer)問題。
示例
@property (nonatomic, assign) NSInteger age;
在這個示例中,age
屬性是一個 assign
引用,這意味著它只是簡單地儲存一個整數值,不涉及引用計數管理。
4. copy
- 適用物件:通常用於需要不可變副本的物件型別(如
NSString
、NSArray
、NSDictionary
)。 - 記憶體管理:
copy
屬性會對物件進行淺複製或深複製,具體取決於物件的實現。當一個物件被賦值給一個copy
屬性時,會建立一個新的副本,並將其賦值給屬性。 - 生命週期:
copy
引用會建立一個新的物件副本,確保屬性持有的物件是獨立的。
示例
@property (nonatomic, copy) NSString *name;
在這個示例中,name
屬性是一個 copy
引用,這意味著當一個物件被賦值給 name
屬性時,會建立一個新的副本,並將其賦值給 name
屬性。
5. unsafe_unretained
- 適用物件:通常用於物件型別,但不推薦使用。
- 記憶體管理:
unsafe_unretained
屬性不會對物件進行強引用計數。當物件被釋放時,unsafe_unretained
屬性不會自動設定為nil
,可能會導致懸掛指標問題。 - 生命週期:
unsafe_unretained
引用不會延長物件的生命週期。
示例
@property (nonatomic, unsafe_unretained) id delegate;
在這個示例中,delegate
屬性是一個 unsafe_unretained
引用,這意味著當 delegate
物件被釋放時,delegate
屬性不會自動設定為 nil
,可能會導致懸掛指標問題。
總結
strong
:用於物件型別,增加引用計數,確保物件不會被釋放。weak
:用於物件型別,不增加引用計數,當物件被釋放時,屬性自動設定為nil
。assign
:用於基本資料型別和非物件型別,不涉及引用計數管理。copy
:用於需要不可變副本的物件型別,建立物件的副本。unsafe_unretained
:用於物件型別,但不推薦使用,不增加引用計數,當物件被釋放時,屬性不會自動設定為nil
。
理解這些屬性修飾符的區別才能更好地管理記憶體,避免記憶體洩漏和懸掛指標問題。