Do I have to continuously declare weak references to break retain cycles for blocks inside of blocks?
__weak typeof(self) weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//do I need to create another weak reference to strongSelf for this block?
[strongSelf doSomething];
}];
}];
I'm afraid so. [strongSelf setMyBlock:<inner block>] will cause self to retain the inner block. If the inner block has a strong reference to self, that's a cycle. The fact that the strongSelf variable was assigned from a __weak qualified variable originally does not make a difference.
As some other users mentioned, you can use the original weakSelf rather than creating a new one. The reason you create a strongSelf reference in the block is that otherwise self might be deallocated while the block is running. strongSelf will either end up nil (if self was deallocated before strongSelf was assigned, but this causes no harm) or else self will not be deallocated while the block is executing, because you have a strong reference. During the time that you have a strong reference to self, the original weakSelf is also safe to use, because self will not be deallocated.
Related
I`ve found that construction __strong typeof(self)self = weakSelf.
It allows remove NSAssert macro self catching, but I am in doubt is it right to use it in that way?
__weak typeof(self)weakSelf = self;
self.signupBlock = ^{
__strong typeof(self)self = weakSelf;
NSLog (#"%d", self.property)
NSAssert((self.property > 5), #"Some message");
}
Pls advice.
Sorry, I had to say first that using of
__strong typeof(self)strongSelf = weakSelf;
construction results to warnings and I suppose to mem cycle, when NSAssert macro used, because it contains self in.
self is just an variable name, so it's perfectly fine to redefine it locally. It might be even preferred to
__strong typeof(weakSelf) strongSelf = weakSelf;
because
it makes for easily readable code
it prevents you for mistakenly referencing "real" self and potentially creating retain cycles.
Additionally, you might want to look at answers to this question for discussion when to use weak / strong self in blocks, and libextobjc library for neat #weakify / #strongify macros.
Change the code to, so that it´s clear that you are referring only to strongSelf in the block:
__weak typeof(self) weakSelf = self;
self.signupBlock = ^{
typeof(weakSelf) strongSelf = weakSelf;
if strongSelf {
NSLog (#"%d", strongSelf.property)
NSAssert((strongSelf.property > 5), #"Some message");
}
}
Your code sets up a weak connection to self __weak typeof(self) weakSelf = self;. Then when it needs to call self later, it sets up a strong connection to self typeof(weakSelf) strongSelf = weakSelf; and checks if self is still around (has not been released) if strongSelf {. If so the strong connection will keep it alive while the rest of the code is run, which might in many instances involve another block to call on the main thread (i.e. hence the strong connection).
NSAssert is only supposed to be used in Objective-C methods, and as such it uses self and _cmd. A block is not an Objective-C method, and so you should not use NSAssert in it. You should probably use NSCAssert instead.
Yeah using self as variable name in ObjC is fine.
I made a fancy macro for such cases where you need to break a retain cycle caused by a stored block:
#define StrongSelf __strong __typeof__((__typeof__(self))self)
#define WeakSelf __weak __typeof__((__typeof__(self))self)
#define RecoverSelf for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO) \
for (StrongSelf this = self; this != nil && _continue_loop; _continue_loop = NO) \
for (StrongSelf self = this; _continue_loop; _continue_loop = NO)
#define WeakenSelf for (BOOL _continue_loop = YES; _continue_loop; _continue_loop = NO) \
for (WeakSelf this = self; _continue_loop; _continue_loop = NO) \
for (WeakSelf self = this; _continue_loop; _continue_loop = NO)
which you can use like that:
WeakenSelf {
_signupBlock = ^{
RecoverSelf {
NSLog (#"%d", self.property)
NSAssert((self.property > 5), #"Some message");
}
}
}
why does it work when we pass the weak reference to a strong reference inside the block? If a local variable in a block is retained, this should add a retain to self and thus create this bad retain cycle?
Here is the example :
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf;
strongSelf.textLabel.text = [result stringValue];
}];
}];
When you create or copy a block (it could be copied when you, for example, schedule it to gcd), referenced variables are captured (unless declared with __block specifier). Strong references are retained, weak references are not.
When you create local strongSelf variable it keeps self alive while block executes (i.e. while it's not executed and sits in a property there's no strong reference). When you reference self directly - self is captured and retained, now it keeps self while block is alive.
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf; // strong reference when block executes
[self foo]; // strong reference when block created/copied
strongSelf.textLabel.text = [result stringValue];
}];
}];
See the difference? If you kill all strong pointers to object with direct self reference there is still one strong reference inside the block, the one which was captured and retained. At the same time local strongSelf pointer only holds strong reference to self while block is executed, so, if self was already dead, weakSelf would be nil and strongSelf will get nil value.
no it doesn't create a cycle since self isn't captured as strong! :)
strongSelf is a strong reference that retains self BUT since strongSelf is a local var, it is released when the block is done and the retain count drops fine
There are a bunch of questions about all these weak and strong selves but I want that you guys took a look at my particular example:
- (void)getItemsWithCompletionHandler:(void (^)(NSArray*items))completionHandler {
__weak __typeof__(self) weakSelf = self;
[self doWorkWithCompletionHandler:^(Response *response) {
// this completion is not on main thread
dispatch_async(dispatch_get_main_queue(), ^{
...
[weakSelf doAnotherWorkWithCompletionHandler:^(Response *response) {
// this completions is not on main thread either
dispatch_async(dispatch_get_main_queue(), ^{
__typeof__(self) strongSelf = weakSelf;
NSArray *itemsIds = [strongSelf doWorkOnMainThread1];
NSArray *items = [strongSelf doWorkOnMainThread2];
completionHandler(items);
});
}];
});
}];
}
Is everything correct here or not? Also you are welcome to suggest a refactoring
If you turn all warnings on, then you will get a warning for
[weakSelf doAnotherWorkWithCompletionHandler... ];
You shouldn't send messages to weak objects. A weak object could disappear while the method that is called is running. Store the weak object into a strong one, the result is either nil or not. If you then call
[strongSelf doAnotherWorkWithCompletionHandler... ];
you know that either strongSelf == nil and nothing happens, or strongSelf is and stays not nil while the method is executing.
You should check if completionHandler is not NULL and then call it.
if (completionHandler) {
completionHandler(items);
}
Otherwise you'll crash if completionHandler is NULL
You may also reconsider if you want to call completionHandler(items) at all if self == nil at any point. I say that, because there is a slight inconsistency.
In line
[weakSelf doAnotherWorkWithCompletionHandler:^(Response *response) {
if weakSelf is nil already, then it's completionHandler will not be called and in result completionHandler(items) will also not be called.
But in here:
__typeof__(self) strongSelf = weakSelf;
NSArray *itemsIds = [strongSelf doWorkOnMainThread1];
NSArray *items = [strongSelf doWorkOnMainThread2];
completionHandler(items);
if self == nil then completionHandler will in fact be called.
Of course I don't see the whole picture and maybe it's completely irrelevant, but something you might want to take under consideration.
Going further, I assume you'd rather have completionHandler called in each and every scenario, even if self == nil at any point. Or add an error parameter to it in case of anything going wrong.
And if you want to be super pedantic, you might want to put __weak after the type, as such:
__typeof__(self) __weak weakSelf = self;
It's the preferred way: https://developer.apple.com/library/ios/releasenotes/objectivec/rn-transitioningtoarc/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4 (look for "You should decorate variables correctly.")
While reading a blog about concurrency in iOS, I stumbled upon the next code:
__weak id weakSelf = self;
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
MyClass* strongSelf = weakSelf;
strongSelf.textLabel.text = [result stringValue];
}];
}];
The author explains that the use of weakref is needed since:
we need to make a weak reference to self, otherwise we create a retain
cycle (the block retains self, the private operation queue retains the
block, and self retains the operation queue). Within the block we
convert it back to a strong reference to make sure it doesn’t get
deallocated while running the block.
I can understand why the block would have retained self, but I don't understand why (and where exactly) the private operation queue retains the block and when/where self retaind the opeation queue. Any explanation would be much appreciated.
try to write this code without weak reference:
[self.operationQueue addOperationWithBlock:^{
NSNumber* result = findLargestMersennePrime();
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.textLabel.text = [result stringValue];
}];
}];
to make this code work - compiler retains reference to self in operationQueue to avoid situation when self is deleted from memory and self.textLabel.text = .. is executed, so it tries to guarantee that object will be alive.
This is where cycle is actually created:
self retains operationQueue (this means that operationQueue cannot be deleted while self is alive)
operationQueue retains self (this means that self cannot be deleted while operationQueue is alive)
to avoid this - you're creating week reference, so you're eliminating 2nd retention
PS. "block" is part of operationQueue, so we can assume just 2 items in this scheme.
This question already has answers here:
capturing self strongly in this block is likely to lead to a retain cycle
(7 answers)
Closed 9 years ago.
I have reqest with block. But the compiler issues a warning
"Capturing 'self' strongly in this block is likely to lead to a retain
cycle"
__weak typeof(self) weakSelf = self;
[generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[#"images"][#"low_resolution"][#"url"]]] placeholderImage:[UIImage imageNamed:#"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(#"success");
[generalInstaImage setImage: image];
[weakSelf saveImage:generalInstaImage.image withName:data[#"id"]];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"fail");
}];
I try example write like weakSelf.generalInstaImage, but then the compiler generates an error and do not compile.
Consider this warning:
Capturing self strongly in this block is likely to lead to a retain
cycle
When you receive the above warning, you should review your block for:
any explicit references to self; or
any implicit references to self caused by referencing any instance variables.
Let's imagine that we have some simple class property that was a block (this will experience the same "retain cycle" warnings as your question, but will keep my examples a little simpler):
#property (nonatomic, copy) void (^block)(void);
And let's assume we had some other class property we wanted to use inside our block:
#property (nonatomic, strong) NSString *someString;
If you reference self within the block (in my example below, in process of accessing this property), you will obviously receive that warning about the retain cycle risk:
self.block = ^{
NSLog(#"%#", self.someString);
};
That is remedied via the pattern you suggested, namely:
__weak typeof(self) weakSelf = self;
self.block = ^{
NSLog(#"%#", weakSelf.someString);
};
Less obvious, you will also receive the "retain cycle" warning if you reference an instance variable of the class inside the block, for example:
self.block = ^{
NSLog(#"%#", _someString);
};
This is because the _someString instance variable carries an implicit reference to self, and is actually equivalent to:
self.block = ^{
NSLog(#"%#", self->_someString);
};
You might be inclined to try to adopt weak self pattern here, too, but you can't. If you attempt the weakSelf->_someString syntax pattern, the compiler will warn you about this:
Dereferencing a __weak pointer is not allowed due to possible null value caused by race condition, assign it to strong variable first
You therefore resolve this by using the weakSelf pattern, but also create a local strong variable within the block and use that to dereference the instance variable:
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
NSLog(#"%#", strongSelf->_someString);
// or better, just use the property
//
// NSLog(#"%#", strongSelf.someString);
}
};
As an aside, this creation of a local strong reference, strongSelf, inside the block has other advantages, too, namely that if the completion block is running asynchronously on a different thread, you don't have to worry about self being deallocated while the block is executing, resulting in unintended consequences.
This weakSelf/strongSelf pattern is very useful when dealing with block properties and you want to prevent retain cycles (aka strong reference cycles), but at the same time ensuring that self cannot be deallocated in the middle of the execution of the completion block.
FYI, Apple discusses this pattern in the "non-trivial cycles" discussion further down in the Use Lifetime Qualifiers to Avoid Strong Reference Cycles section of the Transitioning to ARC Release Notes.
You report that you received some "error" when you referenced weakSelf.generalInstaImage in your example. This is the correct way to resolve this "retain cycle" warning, so if you received some warning, you should share that with us, as well as show us how you declared the property.
Use __unsafe_unretained typeof(self) weakSelf = self