No. Under GC you don't have this problem at all. You don't need weak references or anything else funky, it just works. MyClass1 pointing to MyClass2 and back with ordinary object references/ assign properties does create a cycle yes, however GC can manage that perfectly well. Once there are no references to either MyClass1 or MyClass2 from the *ROOT* objects, even though they point to each other, they are subject to collection. GC is able to deal with these reference loops quite happily.

Of course you’re right, you do not need weak references under GC to break reference count cycles - these are a non-issue under GC. I made the implicit assumption (bad bad!) that these objects should not keep each other alive. This is what __weak is good for: it marks a reference which does not keep the target alive and is auto-niled when the target dies. Depends on what you need.

And there’s no need to conditionalize __weak in any way. It’s simply ignored under non-GC.


Let me see if I can summarize this with an example so the original poster can decide exactly what fits his purpose, because there's still room for misunderstanding.

Assume we start with two objects, O1 and O2, each of which has one strong reference to it (if we're memory managed that means it has been retained once and not yet released, if GC, it's strongly reachable). Then let's say each of the following things happen and I'm going for the sake of example assume no other external factors alter the object lifetimes, try to keep it simple.

1. O1 and O2 are set to point to each other (each has its connection set to the other). 2. The strong reference to O1 is removed, so in memory managed mode it's released, or in GC mode it becomes otherwise non-root-reachable 3. sometime later the strong reference to O2 is removed in the same way as 2. above.

Here is what I believe happens in each of the cases

a) Memory Managed mode where 'connection' is a 'retain' property.
        At 1., the reference counts of O1 and O2 are increased to 2.
        At 2., O1's reference count drops to 1 and it is not released.
        At 3., O2's reference count drops to 1 and it is not released.

        Yes this is your retain cycle as the original poster had said.


b) Memory Managed mode where 'connection' is an 'assigned' property which does self.connection.connection = nil upon dealloc
        At 1. the reference counts of O1 and O2 are unchanged
At 2. O1's reference count drops to 0 and it's released, in doing so it nil's O2's connection pointer At 3. O2's reference count drops to 0 and it's released, its connection pointer was nil'ed earlier, so there's no dangling reference.

This is what the original poster suggested and should work. Note that O2 can 'lose' O1 at any point, its lifetime depends on things entirely external to the ownership of O2, but there's no retain cycle and the reference nil in the dealloc stops one object from trying to use the other after that's happened.


c) GC mode, normal references (ie connection is an assigned ordinary property)
        At 1. O1 and O2 now have mutual strong references to each other
At 2. O1 loses one strong reference however because O2 is still strongly reachable, and O1 is strongly reachable from O2, O1 is *not* subject to reclaimation here. They both continue to hang around. At 3. O2 loses its strong reference. O1 and O2 *still* strongly reference each other however, because they no longer have a path from a root object, they are now subject to being reclaimed.
        
This is what I assumed (and true I have also made an assumption) is the most likely useful case. Unlike in b) where each object could lose its connected object at any point, in c) as long as *one* of the objects is strongly reachable, its reference to its partner keeps its partner object alive, however when *neither* of them are strongly reachable from root objects, the fact they refer to each other only, is not enough to keep them alive. This is where GC wins.


d) GC mode, _weak references between O1 and O2
        At 1. O1 and O2 have weak references to each other
At 2. O1 is now not strongly reachable from the root and, because the reference to O1 from O2 is weak, that does not make a strong reference path and O1 *may* now be collected at any point. Doesn't have to be, the GC can take it anytime it likes. At 2. O2 is also now not strongly reachable and it is also subject to reclaimation. At some point after this O1 and O2 will be collected.

d) is the closest GC analogue to b), it's very much like it. The objects don't affect each other's lifetimes at all, and when one object is collected the reference from the other object is nil'ed as it was in b). The only difference really is that in b) (the way I set this example up), O1 *will* be dealloc'ed at stage 2., the point it's released, in d) it may or may not be dealloced there, or sometime later or never.



I would personally expect that in most cases c) is what you want if you can have it, and it's something garbage collection really helps with. If you really really wanted b), to have these connections not affect the objects on the other end at all, then _weak references will do that in a GC model.

I'm sure I have some errors and poor terminology there and stand ready for correction (or collection).

_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to