How to use strengths and weaknesses with sibling objects (maybe a parent) in Objective-C ARC?

I have two Objective-C objects that are somehow related to each other. You can think of it as a bilateral relationship. With ARC, I understand that a parent must have a strong reference to its child, while the child has a weak reference pointing to the parent. But what if a parent can be either an object? Or if the objects are "brothers and sisters"?

Let's say I have a Person class, and I would like to create two objects whose properties are related to each other.

@implementation Person @property (strong, nonatomic) Person *brother; Person personA = [Person new]; Person personB = [Person new]; personA.brother = personB; personB.brother = personA; 

Would this lead to a hold cycle?

Here is another scenario: let's say I have an Appointment class and a Staff class.

 @implementation Appointment @property (strong, nonatomic) Staff *staff; @implementation Staff @property (strong, nonatomic) NSArray *appointments; 

In a staff view, I may need to show all staff assignments. Therefore, I could create all my objects like this ...

 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]; 

Could this lead to a hold cycle since all links are strong?

Finally, consider this scenario: let's say I changed the Assignment Personnel property to weak.

 @implementation Appointment @property (weak, nonatomic) Staff *staff; 

This may solve the problem for my second (above scenario), but what if I create a new appointment and I want to add a new employee and then transfer the object to another place for processing?

 + (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? } 

Since the property of my staff in Appointment is now weak, is there a chance that it will be set to zero when the garbage collection starts (since there are no strong references to the staff object)?

EDIT: As @dasblinkenlight explained , the app.staff object will still exist, since the local staff variable (from buildAppointment ) is still on the stack. However, if I had:

 + (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? } 

My colleagues seem to have dealt with this using two properties: one strong and one weak:

 @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; } 

Then, when setting personnel properties, they will use setStaffStrong or setStaffWeak, if necessary. However, this seems to be very hacked - is there probably a more elegant solution? How would you build your classes to handle the above scripts?

PS: I apologize for the long question; I tried to explain it as best I could. :)

+4
source share
1 answer

One general point about strong and weak links: strong links indicate ownership, while weak links indicate an association. When neither of the objects belongs to the other, usually there are other objects that belong to them, or both of them have strong references coming from local variables.

Will [class Person ] hold the loop?

Yes, that would be because Person owns his brother, but he shouldn't: it should be a weak property. This should be good, because there must be another object (a list of all persons, a dictionary organizing people by name or something like that) to which all Person objects belong. As long as the Person object is in this collection of faces, it will not be released.

Will [ Appointment and Staff ] lead to a hold cycle because all links are strong?

That's right, that's what happens. NSArray saves the objects that go into it, closing the retention cycle. Note: you cannot make NSArray weak in order to break this cycle: it must be Staff , which becomes weak, not appointments .

Finally, consider this scenario: let's say I change the Appointment Staff property to weak . This may solve the problem for my second (above scenario), but what if I create a new appointment and I want to attach an employee and then transfer the object to another place for processing?

There is no problem with this: the stack Staff variable has a strong reference to it, so it will not be released.

Since my Staff property in Appointment is now weak, is there a chance that it will be set to nil when garbage collection starts (since there are no strong references to the staff object)?

ARC is not a garbage collection system: it is stored and freed up at certain, deterministic times. Staff will not be released, because by default Staff *staff = [Staff new]; is strong.

EDIT: The edited example will really free up the Staff object. However, this example is unusual because it is unlikely that your createAppointment will create a new instance of Staff . Rather, it will grab an existing instance from a registry containing all employees, for example:

 + (Appointment *)createAppointment { Appointment *appt = [Appointment new]; // Registry gives you a reference to an existing Staff. // Since the object remains registered, that not the last strong reference. Staff *staff = [staffRegistry reserveMember]; appt.staff = staff; return appt; } 

staffRegistry is a class that manages (and owns) all Staff objects, storing them in an array, dictionary, or some other collection. All other references to Staff objects (except temporary references to stack variables) should be weak. Thus, removing a member from the registry will also free him from all the destination objects in which he can participate.

My colleagues seem to have dealt with this using two properties: one strong and one weak

If you think it’s a hack, you are 100% right. A strong and weak problem becomes simple when you make a decision about who knows what; You don’t need to come up with a code that promises is a serious service nightmare to access.

+4
source

Source: https://habr.com/ru/post/1496273/


All Articles