I have a circular reference. How can I create a weak reference in Objective-C?


I have a circular reference. How can I create a weak reference in Objective-C?



I'm working on an iPhone application. 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.

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

Every Row contains an NSMutableArray of these Blocks.

@interface Row : NSObject {     NSMutableArray *blocks; } -(void)addBlock:(Block*)aBlock; @end  @implementation Row -(void)addBlock:(Block*)aBlock {     [blocks addObject:aBlock];     aBlock.yCoord = self; } @end 

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?


How optimize sqlite query with dates & substr?

1:

How use sqlite + fdbm library with threading on the iPhone
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 did with a delegate. Exception/Error handling in Objective-C (iPhone app)When using properties, use "assign" instead of "retain" to achieve this. How to show “Done” button on iPhone number padFor example:. How do you duplicate a file in XCode?
@property (nonatomic,assign) Row *yCoord; 
The rest of my answer answer relates to "weak references" in terms of Objective-C 2.0 and GC.. Unit testing an iPhone static library with XCode 3
. Image getting pixelated when used as part of an animation in iPhone animation When you're working with garbage collection (10.5+), a weak reference is created by prefixing a variable declaration with __weak. UITableView Animation HeadacheWhen you assign to this 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 attrialthough e is ignored.). Thus, you must safely modify the above answer to play nicer with garbage collection (currently on 10.5+, and perhaps any day on iPhone) as follows: (See the related Apple docs.).
@property (nonatomic,assign) __weak Row *yCoord; 
To quote Chris Hanson (where you must find more detailed information):.
"By prefixing an instance variable declaration with __weak, you tell the garbage collector this if it's the only reference to an object this the object should be considered collectable.".
I'd clarify this 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, although there is also a __strong attrialthough e, although 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 this 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 must cause retain cycles and memory leaks, the lack of __strong must result in memory stomping and really strange and insidious bugs this occur non-deterministically and must be quite difficult to track down.).

2:

Just change it to assign instead of retain, no more circular references..
@interface Block : UIImageView {   Row *yCoord; } @property (nonatomic,assign) Row *yCoord; @end 

3:

A weak reference is simply an assignment (unless you're talking around Garbage Collection which is a whole separate must of worms, although does not suffer from retain cycles).. Normally, in Cocoa, Row would retain the Block objects (by including them in the NSMutableArray), although 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 must also take the precaution of zeroing the row reference from Blocks before removing the entiries from the array, any thing 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..

4:

Using assign to create weak references must be unsafe in a multithreaded system, particularly when either object must be retained by a third object, and then used to dereference the another object.. Fortunately, this is often a problem of hierarchy, and the object containing the weak reference only cares around the object it refers to for the referred-to object's lifetime. This is the usual position with a Superior<->Subordinate relationship.. I think this the case in the OP's comment maps to this, with Row = Superior, Block = Subordinate.. In this case, I would use a handle to refer to the Superior from the Subordinate:.
// Superior.h  @class Superior;  @interface SuperiorHandle : NSObject {     @private         Superior* superior_; }  // note the deliberate avoidance of "nonatomic" @property (readonly) Superior *superior;  @end  @interface Superior : NSObject {     @private         SuperiorHandle *handle_;         // add one or more references to Subordinate instances }  // note the deliberate avoidance of "nonatomic" @property (readonly) SuperiorHandle *handle;  @end   // Superior.m  #import "Superior.h"  @implementation SuperiorHandle  @synthesize     superior = superior_;  - (id)initWithSuperior:(Superior *)superior {     if ((self = [super init])) {         superior_ = superior; // weak reference     } }  - (void)invalidate {     @synchronized (self) {         superior_ = nil;     } }  - (Superior *)superior {     @synchronized (self) {         // retain and autorelease is required to prevent dealloc before we're ready, thanks to AndroidDev for pointing out this mistake         return [[superior_ retain] autorelease];     } }  @end  @implementation Superior  @synthesize     handle = handle_;  - (id)init {     if ((self = [super init])) {         handle_ = [[SuperiorHandle alloc] initWithSuperior:self];     }     return self; }  - (void)dealloc {     [handle_ invalidate];     [handle_ release];      [super dealloc]; }  @end   // Subordinate.h  @class Superior; @class SuperiorHandle;  @interface Subordinate : NSObject {     @private         SuperiorHandle *superior_handle_; }  @property (readonly) Superior *superior;  @end   // Subordinate.m  #import "Subordinate.h"  #import "Superior.h"  @implementation Subordinate  // no synthesize this time, superior's implementation is special  - (id)initWithSuperior:(Superior *)superior {     if ((self = [super init])) {         superior_handle_ = [superior.handle retain];     }     return self; }  - (void)dealloc {     [superior_handle_ release];      [super dealloc]; }  - (Superior *)superior {      @synchronized (superior_handle_) {         return superior_handle_.superior;      } }  @end 
Some advantages:.
  1. It's thread safe. There is no way you must have the weak reference contained in Subordinate become an invalid pointer. It may become nil although this is OK.
  2. Only the objects themselves need to know around the embedded weak reference. All another objects must treat Subordinate as if it has a regular reference to Superior.


32 out of 100 based on 22 user ratings 62 reviews