Reference to self inside block

2020-02-29 10:13发布

Right now I have a portion of code like this:

__strong MyRequest *this = self;

 MyHTTPRequestOperation *operation = [[MyHTTPRequestOperation alloc]initWithRequest:urlRequest];
 [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *request, id responseObject) {
     [this requestFinished:request];
 }
 failure:^(AFHTTPRequestOperation *request, NSError *error) {
     [this requestFailed:request withError:error];
 }];

I am mainly doing this because some other classes are inheriting from the class where this code is located and implementing their own requestFinished and requestFailed.

If I change the self reference to __weak I start getting some EXC_BAD_ACCESS errors. With a __strong reference everything works fine but I'm afraid about creating a retain cycle. Note that i am using ARC.

Is this code creating a retain cycle that will cause problems? Any simple solution to this? Any different approach that I can follow to let inheriting classes implement their own methods to handle responses?

1条回答
我命由我不由天
2楼-- · 2020-02-29 10:56

Yes, it creates a retain cycle. Does it cause problems? Maybe.

If the API supports it, you can reset the handlers, which will break the retain cycle manually:

[operation setCompletionBlockWithSuccess:nil failure:nil];

Or you can use a weak reference. However, you say you tried a weak reference, and it crashed. A weak reference is guaranteed to be either nil at the start of a message, or remain valid until the message has been processed. In other words, consider...

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    [weakSelf doSomething];
});

If weakSelf is nil when the asynchronous block executes, then "nothing" happens. If it is not nil, then it is guaranteed to be retained at least until doSomething has finished. In effect, it is similar to this:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    { id obj = weakSelf; [weakSelf doSomething]; obj = nil; }
});

Note, however, that if you did this:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    [weakSelf doSomething];
    [weakSelf doSomethingElse];
});

that the object could become nil in-between doSomething and doSomethingElse.

Furthermore, if you access an instance variable via a weak reference, you are just asking for a SEGV:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    foo = weakSelf->someIVar; // This can go BOOM!
});

Thus, if your handler is accessing the weak reference for a single message, then you should be fine. Anything else should do the "Weak-Strong-Dance."

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    MyRequest *strongSelf = weakSelf;
    if (!strongSelf) return;
    [strongSelf doSomething];
    [strongSelf doSomethingElse];
    foo = strongSelf->someIVar;
});

If you think you are following the guidelines, then maybe a more complete source code example, with the crash details would help...

查看更多
登录 后发表回答