1
votes

I'm currently thinking about how to prevent strong reference cycles when using blocks that retain self. The usual way seems to be to just use a weak reference to self:

@property (strong, nonatomic) NSOperationQueue *queue;

- (void)methodA {
    __weak id *weakSelf = self;
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [weakSelf methodB];
    }];
    [self.queue addOperation:operation];
}

But what if methodB looks like this:

- (void)methodB {
    [self someOtherMethod];
}

Would this still cause a strong reference cycle? Or would methodB receive the weak reference to self from methodA as its reference to self? (That is, is methodB's reference to self just a strong reference to the weak reference from methodA?)

2
How is this a reference cycle given only one object is being used?trojanfoe
My understanding is this: If the block had a strong reference to self and not a weak one, then the object referred to by self could not be freed because the block would hold a reference to it. The block on the other hand could not be freed because it is referenced by self (via queue.) The question is, does methodB with a syntactically strong reference to self re-introduce this cycle even though the block's reference is weak.aus
you might be right, however it's not freed is it, it's released (retain count--) so when the block terminates the object will be destroyed, so it'll probably be OK.trojanfoe
I guess you could say deallocated instead of freed. I meant removing the object from memory after the retain count reached zero.aus
@trojanfoe Lets assume the queue gets suspended and all strong references to the object (referred to by self) but the ones within the block are removed.aus

2 Answers

1
votes

Or would methodB receive the weak reference to self from methodA as its reference to self? (That is, is methodB's reference to self just a strong reference to the weak reference from methodA?)

A method does not "receive" a strong or weak reference. It receives a reference. "Strong" or "weak" only apply to a variable (usually, an instance variable or variable captured by a block).

weakSelf is a weak reference in the block. Because weakSelf is a zeroing weak reference (__weak), either it points to a valid object, or its value is nil. If the former, it points to a valid object, and methodB is called on it. If the latter, sending a message to nil does nothing, so nothing happens.

You ask if the self in methodB is a strong reference. A strong reference means that it is retained, so if self were a strong reference in methodB, that means it retains self at the beginning of the method and releases it at the end. But why does it matter whether the method retains an argument such as self? Retain cycles refer to objects strongly referencing each other. A function or method will run and then stop; any retains they do on local variables must be temporary by the memory management rules, and have no effect on retain cycles. (The technical answer is no, self is not retained in ARC, and arguments including self are generally never retained in MRC. But as I said this really isn't relevant.)

-1
votes

I finally found a part in the documentation that kind of answers this question. So it really looks like methodB receives the block's weak reference to self.