[英]How do I use strong and weak with sibling objects (either can be the parent) in Objective-C ARC?
我有兩個Objective-C對象以某種方式相互關聯。 你可能會認為這是一種雙向關系。 使用ARC,我理解父對象應該對其子對象持有強引用,而子對象持有指向其父對象的弱引用。 但是,如果父母可以是對象呢? 或者如果對象是“兄弟姐妹”?
假設我有一個Person類,我想實例化兩個兄弟屬性相互指向的對象。
@implementation Person
@property (strong, nonatomic) Person *brother;
Person personA = [Person new];
Person personB = [Person new];
personA.brother = personB;
personB.brother = personA;
這不會導致保留周期嗎?
這是另一種情況:假設我有一個約會課和職員班。
@implementation Appointment
@property (strong, nonatomic) Staff *staff;
@implementation Staff
@property (strong, nonatomic) NSArray *appointments;
在工作人員看來,我可能想要顯示所有工作人員的約會。 因此我可以實例化我的所有對象......
Staff *bob = [Staff new];
Appointment *apptA = [Appointment new];
Appointment *apptB = [Appointment new];
apptA.staff = bob;
apptB.staff = bob;
bob.appointments = [NSArray arrayWithObjects:apptA, apptB, nil];
由於所有參考文獻都很強大,這不會導致保留周期嗎?
最后,請考慮這種情況:假設我將約會的員工財產更改為弱。
@implementation Appointment
@property (weak, nonatomic) Staff *staff;
這可能會解決我的第二個問題(上面的場景),但是如果我創建一個新的約會並且我想要附加一個新的工作人員,然后將該對象傳遞到其他地方進行處理呢?
+ (void)buildAppointment {
Appointment *appt = [Appointment new];
Staff *staff = [Staff new];
appt.staff = staff;
[self saveAppointment:appt];
}
+ (void)saveAppointment:(Appointment *)appt {
// Do something with appt here.
// Will I still have appt.staff?
}
因為我在Appointment上的staff屬性現在很弱,所以在垃圾收集運行時是否有可能將它設置為nil(因為沒有對staff對象的強引用)?
編輯:正如@dasblinkenlight 解釋的那樣 , app.staff
對象仍然存在,因為本地staff
變量(來自buildAppointment
)仍在堆棧中。 但是,如果我有:
+ (void)createAndSaveAppointment {
Appointment *appointment = [self createAppointment];
[self saveAppointment:appointment];
}
+ (Appointment *)createAppointment {
Appointment *appt = [Appointment new];
Staff *staff = [Staff new];
appt.staff = staff;
return appt;
}
+ (void)saveAppointment:(Appointment *)appt {
// Do something with appt here.
// Will I still have appt.staff?
}
我的同事似乎通過使用兩個屬性來處理它,一個強大而另一個弱:
@implementation Appointment
@property (strong, nonatomic) Staff *staffStrong;
@property (weak, nonatomic) Staff *staffWeak;
- (Staff *)staff {
if (staffStrong != nil) {
return staffStrong;
}
return staffWeak;
}
- (void)setStaffStrong:(Staff *)staff {
staffStrong = staff;
staffWeak = nil;
}
- (void)setStaffWeak:(Staff *)staff {
staffStrong = nil;
staffWeak = staff;
}
然后在設置staff屬性時,他們會根據需要使用setStaffStrong或setStaffWeak。 然而,這似乎非常hacky - 當然有一個更優雅的解決方案? 你將如何建立你的類來處理我的上述場景?
PS:我為這個長期問題道歉; 我盡力解釋它。 :)
關於強與弱參考的一般說明:強引用表示所有權 ,而弱引用表示關聯 。 當兩個對象都不擁有另一個對象時,通常有其他對象擁有它們,或者它們都有來自局部變量的強引用。
[
Person
類]不會導致保留周期嗎?
是的,它會,因為一個Person
擁有他的兄弟,但他不應該:這應該是一個弱的財產。 它應該沒問題,因為應該有另一個對象(所有人的列表,一個按名稱組織人員的字典,或類似的東西)擁有所有Person
對象。 只要Person
對象在該人員集合中,它就不會被釋放。
由於所有參考文獻都很強,[
Appointment
和Staff
]是否會導致保留周期?
正確,即將發生的事情。 NSArray
保留進入它的對象,關閉保留周期的循環。 請注意,你不能讓NSArray
弱到打破這個循環:它需要是變弱的Staff
,而不是appointments
。
最后,請考慮這種情況:假設我將
Appointment
的staff
財產變為weak
。 這可能會解決我的第二個問題(上面的場景),但如果我創建一個新約會並且我想附加一個工作人員,然后將該對象傳遞到其他地方進行處理,該怎么辦?
沒有問題:堆棧變量staff
有一個強大的參考,所以它不會被釋放。
因為我在Appointment上的
staff
屬性現在很弱,所以在垃圾收集運行時是否有可能將它設置為nil(因為沒有對staff對象的強引用)?
ARC不是垃圾收集系統:保留和釋放發生在特定的確定性時間點。 staff
不會被釋放,因為Staff *staff = [Staff new];
默認是強大的。
編輯:編輯的示例將確實釋放Staff
對象。 但是,這樣的例子很不尋常,因為你的createAppointment
不太可能創建一個新的Staff
實例。 相反,它會從包含所有員工成員的注冊表中獲取現有實例,如下所示:
+ (Appointment *)createAppointment {
Appointment *appt = [Appointment new];
// Registry gives you a reference to an existing Staff.
// Since the object remains registered, that's not the last strong reference.
Staff *staff = [staffRegistry reserveMember];
appt.staff = staff;
return appt;
}
staffRegistry
是一個管理(並擁有)所有Staff
對象的類,將它們保存在數組,字典或其他集合中。 對Staff
對象的所有其他引用(除了堆棧變量的臨時引用之外)應該很弱。 這樣從注冊表中刪除成員也會將他從他可能參與的所有約會對象中釋放出來。
我的同事似乎通過使用兩個屬性來處理它,一個強大,另一個弱
如果你認為這是一個黑客攻擊,你是100%正確的。 一旦你決定誰知道什么,那么強與弱的問題就會變得簡單明了。 你不需要提出代碼來承諾一些嚴重的維護噩夢來解決它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.