views:

1841

answers:

3

I have an object of class Row that needs to release numerous objects of the class Block. Every Block currently has a property that retains an instance variable of class Row. Every Row contains an NSMutableArray of these Blocks. I understand that this is a circular reference. Apple's documentation states that in order to deallocate an object with a circular reference I need a weak reference instead of a strong reference (a retain property), but it doesn't follow through and explain how exactly I go about doing so. I plan to release and dealloc all Blocks within a Row as well as the Row itself simultaneously. How do I set up a weak reference within each of my Blocks to their "parent" Row?

EDIT: This is for an iPhone application.

EDIT AGAIN:

The context is this bit of code.

@interface Block : UIImageView {
  Row *yCoord;
}
@property (nonatomic,retain) Row *yCoord;
@end
+5  A: 

Edit: Since the asker clarified he's not using garbage collection (iPhone currently does not support it), my advice is to avoid cycles by having only one of the objects retain the other, just as you would do with a delegate. When using properties, use "assign" instead of "retain" to achieve this. For example:

@property (nonatomic,assign) Row *yCoord;

The rest of my answer answer relates to "weak references" in terms of Objective-C 2.0 and GC.


When you're working with garbage collection (10.5+), a weak reference is created by prefixing a variable declaration with __weak. When you assign to that variable, the GC (if enabled) keeps track of the reference and will zero it out for you automatically if all strong references to the referenced object disappear. (If GC is not enabled, the __weak attribute is ignored.)

Thus, you can safely modify the above answer to play nicer with garbage collection (currently on 10.5+, and perhaps someday on iPhone) as follows: (See the related Apple docs.)

@property (nonatomic,assign) __weak Row *yCoord;

To quote Chris Hanson (where you can find more detailed information):

"By prefixing an instance variable declaration with __weak, you tell the garbage collector that if it's the only reference to an object that the object should be considered collectable."

I'd clarify that by saying "if there are no non-weak references to an object". As soon as the last strong reference is removed, the object may be collected, and all weak references will be zeroed automatically.

Note: This isn't directly related to creating weak references, but there is also a __strong attribute, but since Objective-C object variables are strong references by default, it is generally used only for raw C pointers to things like structs or primitives that the Garbage Collector will not treat as roots, and will be collected from under you if you don't declare them as strong. (Whereas the lack of __weak can cause retain cycles and memory leaks, the lack of __strong can result in memory stomping and really strange and insidious bugs that occur non-deterministically and can be quite difficult to track down.)

Quinn Taylor
Let me clarify that this is for an iPhone application. I don't believe the iPhone uses a GC.
Tozar
so instead of declaring Row *yCoord;with @property(nonatomic,retain) Row *yCoord;Do I do:__weak Row *yCoord;But then how do I declare the property?
Tozar
You can mix @property and __weak: @property(nonatomic,retain) __weak Row *yCoord;
Tim
Also, be aware that iPhone uses what's called "Modern Runtime", so you should be able to omit the ivar declaration and just use the @property, which eliminates some code duplication. (On the Mac, only 64-bit apps use Modern Runtime — 32-bit apps use "Legacy Runtime" for compatibility reasons.)
Quinn Taylor
I appreciate the information but I don't think my problem has been addressed. I would like to implement a similar structure to delegates and subviews, but I have no idea how to declare the Row in the Block class as a weak reference so that the retain count is not incremented.
Tozar
In light of the code sample you've added, here is my advice: If you don't want a Block to retain its parent Row object, just replace "retain" with "assign" in the @property declaration. (Added to my answer.)
Quinn Taylor
Thanks, I believe this is what I was looking for.
Tozar
+2  A: 

A weak reference is simply an assignment (unless you're talking about Garbage Collection which is a whole separate can of worms, but does not suffer from retain cycles).

Normally, in Cocoa, Row would retain the Block objects (by including them in the NSMutableArray), but Block would not retain Row, each would simply store it in an ivar (with an "assign" property).

As long as Row is careful to release each Block before it is deallocated (ie, its dealloc should release the NSMutableArray which will release the Blocks as long as no one else has any pointers to them) then everything will be deallocated as appropriate.

You can also take the precaution of zeroing the row reference from Blocks before removing the entiries from the array, something like:

- (void) dealloc {
    for (Block* b in _blocks) {
        b.row = nil;
    }
    [_blocks release];
    [super dealloc];
}

where _blocks is the ivar referenced by the blocks property.

Peter N Lewis
Is _b the NSMutableArray ivar returned by self.blocks? If so, I'm assuming you mean [_b release] instead. Also, there's no need to use self.blocks inside the class that holds the referencs — just use for (Block* b in _b). It might be less confusing if _b were named "_blocks" or even "blocks". (I realize some people prefer the underscore, but I never use it.)
Quinn Taylor
Fixed, thanks Quinn
Peter N Lewis
A: 

Just change it to assign instead of retain, no more circular references.

@interface Block : UIImageView {
  Row *yCoord;
}
@property (nonatomic,assign) Row *yCoord;
@end
Corey Floyd