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 {
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 {
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. :)