2

I have been struggeling with this issue for a while since i don't think i fully understand the retain cycles. I am totally new to this and i'm trying to learn more about it.

I am getting the EXC_BAD_ACCESS message with the following code.

I started using the weakSelf because i get 2 warnings about the retain cycle if i just use self.successBLock();. The exact warning is:

Capturing 'self' strongly in this block is likely to lead to a retain cycle

Maybe i shouldn't even bother using the weak but i am no so sure about this.

This is the part where i use the weakSelf in a block:

__weak Request *weakSelf = self;

[_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    weakSelf.successBlock(operation.response, responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    weakSelf.failureBlock(operation.response, error);
}];

This is how i assign the block properties:

typedef void (^successBlock)(NSHTTPURLResponse *response, id responseObject);
typedef void (^failureBlock)(NSHTTPURLResponse *response, NSError *error);

@property (nonatomic, copy) successBlock successBlock;
@property (nonatomic, copy) failureBlock failureBlock;
Nipje
  • 43
  • 1
  • 4

2 Answers2

9

A __weak reference is set to nil if the object it points to is deallocated. So if your Request object has already been deallocated when the completion block is called, weakSelf is nil. In that case weakSelf.successBlock evaluates to a NULL pointer, and that is causing the crash.

The following pattern avoids this problem:

[_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    Request *strongSelf = weakSelf;
    if (strongSelf) {
        strongSelf.successBlock(operation.response, responseObject);
    }
} ...

strongSelf will be nil if the Request object has already been deallocated. Otherwise the strong reference ensures that the object is not deallocated while the block is executing.

On the other hand, if you want the Request object to exist until the completion block is called, then you should not use a weak reference.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • When i try your pattern it never enters the if statement. It does enter the failure or success block. Do you know what causes this? Also when i change __weak to __strong the code seems to work. This was just something i tried and i am not sure if this is a correct solution. – Nipje May 08 '13 at 14:12
  • @user2362596: Using `self` in the block can be the correct solution (that's what I meant with the last sentence in my answer). You'll have a "temporary retain cycle" while the operation is executing. As soon as the operation finishes and the completion block is called, the captured self is gone and the retain cycle is broken. – Martin R May 08 '13 at 14:16
  • But this leaves me with the warning which you usually do not want: Capturing 'self' strongly in this block is likely to lead to a retain cycle. I know i probably should ignore this warning but is there any way to get this message not to show? – Nipje May 08 '13 at 14:27
  • @user2362596: You can suppress the warning with a #pragma directive. See http://stackoverflow.com/a/12220731/1187415 for an example. – Martin R May 08 '13 at 14:30
0

When weakSelf is set to nil, weakSelf.successBlock is fine, but weakSelf.successBlock(operation.response, responseObject) will crash.

Nix Wang
  • 814
  • 10
  • 18