block is likely to lead a retain cycle [duplicate] - ios

This question already has an answer here:
Blocks retain cycle from naming convention?
(1 answer)
Closed 8 years ago.
I've written the following category for NSOperationBlock
#implementation NSOperationQueue (Extensions)
-(void)addAsynchronousOperationWithBlock:(void (^)(block))operationBlock
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
block signal = ^ {
dispatch_semaphore_signal(semaphore);
};
[self addOperationWithBlock:^{
operationBlock(signal);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
}];
}
#end
it seems to work properly but when I call it (as shown in the following snippet) I get a warning:
block is likely to lead a retain cycle
[_queue addAsynchronousOperationWithBlock:^(block signal) {
[self foo:nil];
signal();
}];
foo is a method of the class that uses this category.
The same code with addOperationWithBlock: (from NSOperationQueue) doesn't show the warning:
[_queue addOperationWithBlock:^ {
[self foo:nil];
}];
I really don't understand it.
Particularly what I don't understand is:
should I actually use the weak pointer in both the cases? will actually the two snippet bring to a retain cycle in case I don't use the weak pointer?

When you use self within a block, it is captured by the block and could lead to a retain cycle. To cycle occurs when self (or something it has a strong reference to) has a strong reference to the block. To avoid the potential cycle, declare a weak pointer and use that in the block instead:
YourClassName * __weak weakSelf = self;
[_queue addAsynchronousOperationWithBlock:^(block signal) {
[weakSelf foo:nil];
}];

To distill what others have written here:
Neither code example creates a long-lasting retain cycle of the sort
that will strand memory.
Xcode complains about your addAsynchronousOperationWithBlock method because it has a suspicious name. It doesn't complain about addOperationWithBlock because it has special knowledge about addOperationWithBlock that overrides its suspicions.
To get rid of the warning, use __weak (see the answers by jszumski and matt) or rename addAsynchronousOperationWithBlock to not start with "add" or "set".
To elaborate a bit on these:
If self owns _queue, you will have a short-lived retain cycle. self will own _queue, which will own the blocks, and the block that calls [self foo:] will own self. But once the blocks have finished running, _queue will release them, and the cycle will be broken.
The static analyzer has been programmed to be suspicious of method names starting with "set" and "add". Those names suggest that the method may retain the passed block permanently, possibly creating a permanent retain cycle. Thus the warning about your method. It doesn't complain about -[NSOperationQueue addOperationWithBlock:] because it's been told not to, by someone who knows that NSOperationQueue releases blocks after running them.
If you use __weak the analyzer won't complain because there won't be the possibility of a retain cycle. If you rename your method the analyzer won't complain because it won't have any reason to suspect your method of permanently retaining the block passed to it.

The answer from jszumski is correct in essence, but it is important to get the form of the "weak self" dance correct. The form (building on his code) is:
YourClassName * __weak weakSelf = self;
[_queue addAsynchronousOperationWithBlock:^(block signal) {
YourClassName * strongSelf = weakSelf;
if (strongSelf)
[weakSelf foo:nil];
}];
Thus we capture weakSelf through a strong reference. If you don't do that, weakSelf can go out of existence while you are in the middle of using it (because your reference to it is weak).
See my book for the dance, and for other things you can do about potential retain cycles caused by blocks:
http://www.apeth.com/iOSBook/ch12.html#_unusual_memory_management_situations

Related

Modifying a semaphore stored in an instance variable from within an Objective-C block

Apple offers a CPU and GPU Synchronization sample project that shows how to synchronize access to shared resources between CPU and GPU. To do so, it uses a semaphore which is stored in an instance variable:
#implementation AAPLRenderer
{
dispatch_semaphore_t _inFlightSemaphore;
// other ivars
}
This semaphore is then defined in another method:
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
{
self = [super init];
if(self)
{
_device = mtkView.device;
_inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight);
// further initializations
}
return self;
}
MaxBuffersInFlight is defined as follows:
// The max number of command buffers in flight
static const NSUInteger MaxBuffersInFlight = 3;
Finally, the semaphore is utilized as follows:
/// Called whenever the view needs to render
- (void)drawInMTKView:(nonnull MTKView *)view
{
// Wait to ensure only MaxBuffersInFlight number of frames are getting processed
// by any stage in the Metal pipeline (App, Metal, Drivers, GPU, etc)
dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER);
// Iterate through our Metal buffers, and cycle back to the first when we've written to MaxBuffersInFlight
_currentBuffer = (_currentBuffer + 1) % MaxBuffersInFlight;
// Update data in our buffers
[self updateState];
// Create a new command buffer for each render pass to the current drawable
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = #"MyCommand";
// Add completion hander which signals _inFlightSemaphore when Metal and the GPU has fully
// finished processing the commands we're encoding this frame. This indicates when the
// dynamic buffers filled with our vertices, that we're writing to this frame, will no longer
// be needed by Metal and the GPU, meaning we can overwrite the buffer contents without
// corrupting the rendering.
__block dispatch_semaphore_t block_sema = _inFlightSemaphore;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(block_sema);
}];
// rest of the method
}
What I fail to understand here is the necessity of the line
__block dispatch_semaphore_t block_sema = _inFlightSemaphore;
Why do I have to copy the instance variable into a local variable and mark this local variable with __block. If I just drop that local variable and instead write
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
dispatch_semaphore_signal(_inFlightSemaphore);
}];
It seems to work as well. I also tried to mark the instance variable with __block as follows:
__block dispatch_semaphore_t _bufferAccessSemaphore;
This compiles with Clang and seems to work as well. But because this is about preventing race conditions I want to be sure that it works.
So the question is why does Apple create that local semaphore copy marked with __block? Is it really necessary or does the approach with directly accessing the instance variable work just as well?
As a side note, the answer to this SO question remarks that marking instance variables with __block can't be done. The answer is according to gcc but why would Clang allow this if it shouldn't be done?
The important semantic distinction here is that when you use the ivar directly in the block, the block takes a strong reference to self. By creating a local variable that refers to the semaphore instead, only the semaphore is captured (by reference) by the block, instead of self, reducing the likelihood of a retain cycle.
As for the __block qualifier, you'd normally use that to indicate that a local variable should be mutable within the referencing block. However, since the semaphore variable is not mutated by the call to signal, the qualifier isn't strictly necessary here. It still serves a useful purpose from a style perspective, though, in the sense that it emphasizes the lifetime and purpose of the variable.
On the topic of why an ivar can be qualified with __block,
why would Clang allow this if it shouldn't be done?
Perhaps exactly because capturing an ivar in a block implies strongly capturing self. With or without a __block qualifier, if you use an ivar in a block, you're potentially running the risk of a retain cycle, so having the qualifier there doesn't create additional risk. Better to use a local variable (which, by the way, could be a __weak reference to self just as easily as a __block-qualified reference to an ivar) to be explicit and safe.
I think warrenm correctly answered your question as to why one would use a local variable rather than the ivar (and its implicit reference to self). +1
But you asked about why a local variable would marked as __block in this case. The author could have done that to make his/her intent explicit (e.g., to indicate the variable will outlive the scope of the method). Or they could have potentially done it for the sake of efficiency (e.g., why make a new copy of the pointer?).
For example, consider:
- (void)foo {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(4);
NSLog(#"foo: %p %#", &semaphore, semaphore);
for (int i = 0; i < 10; i++) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(#"bar: %p %#", &semaphore, semaphore);
[NSThread sleepForTimeInterval:1];
dispatch_semaphore_signal(semaphore);
});
}
}
While these are all using the same semaphore, in the absence of __block, each dispatched block will get its own pointer to that semaphore.
However, if you add __block to the declaration of that local semaphore variable, and each dispatched block will use the same pointer which will be sitting on the heap (i.e. the address of &semaphore will be the same for each block).
It’s not meaningful here, IMHO, where there’s only one block being dispatched, but hopefully this illustrates the impact of __block qualifier on local var. (Obviously, the traditional use of __block qualifier is if you’re changing the value of the object in question, but that’s not relevant here.)
... marking instance variables with __block can't be done [in gcc] ... but why would Clang allow this if it shouldn't be done?
Regarding why no error on __block for ivars, as that referenced answer said, it’s basically redundant. I’m not sure that just because something is redundant that it should be disallowed.

Weak self is getting nil inside the block but i want to use self object inside the block

I have written a sample code to make a server connection. Please find the code that I have written below.
__weak typeof(self) weakSelf = self;
self.dataTask = [defaultSession dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
weakSelf.dataTask = nil;
NSInteger extractionResponseCode = [((NSHTTPURLResponse *)response) statusCode];
if (!error && data.length > 0 && extractionResponseCode == 200)
{
[weakSelf handleResponse:data];
}
else
{
[weakSelf handleError:error];
}
}];
After getting the response I have to call either handleResponse: or handleError: based on the response.
I have taken weakSelf to avoid retain cycle problem in ARC.
My problem here is inside the block weakSelf is getting as nil so neither handleResponse: nor handleError: methods are called.
Could you please help me how can I resolve this issue.?
Thanks in advance.
The answer is to capture a strong reference. You don't have a retain cycle anyway, unless self has a reference to the completion block. And the strong reference will be released anyway, when the block returns, which will break the cycle if you do happen to have one.
I really wonder, why people think that you need to weakify self every time you capture it.
As the term retain cycle says, you can only have one, if you have a reference to an object that refers to the object holding the first reference (directly or via a number of other references).
So if the block context refers to self, you have a reference cycle, if and only if the block is referred by self. (BTW: This applies to every (strong) reference. There is nothing special about self in Objective-C, nowhere.) You do not have that. Preventing from retain cycles is no reason to weakify self in your case.
However, some want to weakify it, to make self nil in such a case. This is the intention. This can be an advantage under some circumstances: Simply think of a model object that is gone while downloading data for it. There is no reason to keep it alive.
If you do not want that, simply do not weakify self. It is that simple.
The idea is that downloading data shouldn't keep your object alive. If your object goes away while the download is running (for example if the user switches from the screen causing the download to aother screen) then you should just ignore the result and throw it away, or maybe store it to a file, but you should allow self to become nil.
This has nothing to do with a reference cycle: self will go away eventually if you don't use weakSelf, but you shouldn't keep it alive longer than needed. Worst case, you might show an error alert to the user about a screen that has long gone. A failing URL request might take 60 seconds to fail, so the user might do something completely different already.
The correct way to use weakSelf is to assign it to a new variable strongSelf in your callback, then check that it is not nil. Using weakSelf directly is bad because it can become nil at any time.

Memory Management in a Block Using Notifications

According to the Xcode instruments, my code has a memory leak (at #3). But I get the feeling I'm missing something in my mental model of what's going on, so I have a few questions about the following logic:
__block MyType *blockObject = object; //1
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.selectedObjects containsObject:blockObject]) { //2
[self.selectedObjects removeObject:blockObject];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectDeselectionNotification object:blockObject]; //3
} else {
[self.selectedObjects addObject:blockCart];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectSelectionNotification object:blockCart];
}
});
1) I'm using a __block reference because I'm executing this code async and don't want a reference to this variable copied to the heap. Is this a valid usage of __block even though I'm not mutating the variable?
2) Calling self.selectedObjects will create a retain on self. Does the block automatically release this after it has exited?
3) I apparently have a leak at this point, but I'm not exactly sure why. Is NotificationCenter retaining my __block object that is supposed to be disposed of after my block exits?
From the code you've shown, I don't see any problems...
1) Your object would not be "copied" onto the heap - it is already on the heap being an alloc'd object. Rather, it's reference count would be incremented by 1 as it is now owned by the block. You do not need the __block reference as you are not assigning anything to the pointer. In fact, you do not need blockObject at all and can just pass object.
2.) self should be released once the block is done. However, post a notification is synchronous (this block will not finish until all the objects responding to the notification are done).
3.) I'm not sure what the exact implementation that NSNotificationCenter uses, but it doesn't really matter because the posting is synchronous. It will call every observer of your notification and the selectors they want to receive your notification on
It seems as though you are running all this code within another block - can you paste the full method?
Please remove this answer if incorrect (you've already accepted) but I'm not sure you accepted because the answer worked for you.
I don't think you should be referencing self in that block - you will be creating a retain cycle.
__weak YourClass *weakSelf = self;
use weakSelf instead and cut the tie between the creator and the block floating on the dispatch queue?

Is it absolutely leaks when "self" appeared in block?

- (void)netServiceDidResolveAddress:(NSNetService *)service {
dispatch_async(self.downloadQueue, ^{
NSData *data = [self downloadFromRemoteService:service];
dispatch_async(self.storeQueue, ^{
int img = [self.imageStore addImage:data];
dispatch_saync(self.renderQueue, ^{
[self renderThumbnail:img];
dispatch_async(dispatch_get_main_queue(), ^{
[[self thumbnailViewForId:img] setNeedsDisplay:YES];
});
});
});
});
}
this is the code from Apple WWDC2012 《Asynchronous Design Patterns with Blocks, GCD, and》,'self' as strong reference in blocks, Is this code all right? or how to avoid leaks in this situation?
No, self will not leak. self will however retained until after the last block has been executed. When the last block finished, the block gets deallocated which in turn releases self. At that time, and only IFF there are no other strong references to self, it will be deallocated.
Edit:
I could not resist to mention this (because the sample is from Apple himself -- take it with a grain if salt ;) )
So, at the very top there is the method downloadFromRemoteService. It's glaringly obvious that this is a network request. Network requests are inherently _asynchronous_.
One attribute of an asynchronous operation is that this operation cannot be made "synchronous" in a truly manner anymore. Once asynchronous - always asynchronous.
What's also obvious from the code sample, that the network request is oddly enough synchronous, Ohps!
What happens when wrapping a asynchronous task into a synchronous wrapper? Well, its at least "suboptimal": the calling thread will be blocked immediately until the result is available, then just return the result. That's a quite big amount of waste for resources (threads are limited and are costly to create and require a quite amount of RAM).
So, this code has a "code smell". It's a "bad programming practice". We should make this better. ;)
Objects automaticaly retained when mentioned in block. They got released when block deallocated. So this code is all right. Problems occur when your's self-object takes ownership of such blocks with self inside.
So you just need to release block when you don't need it any more.
There is a retain cycle in this code, as self retains self.downloadQueue (and the other queues), which retains all the blocks dispatched to it, including the block here, which in turn retains self when it is copied (which happens when it is dispatched to the queue).
However, it is a temporary retain cycle, because once the block is executed on the queue, the queue will (hopefully) release it, breaking the cycle.

Is This Safe? Possible Retain Cycle on Singleton as Self in Block

I'm pretty sure this is 100% safe, but I don't want to miss anything. I have the following code
- (void) scheduleControlSurfaceProcess {
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
// do something
[self scheduleControlSurfaceProcess];
}];
}
where self is a Singleton. The block works splendidly as a non-main-thread thread. I do not see any memory problems in the profiler (which I don't trust much).
So, may I ignore the warning, "Block will be retained by an object strongly retained by the captured object?" If not, how can I insist that the block to get released (with ARC)? Getting the warning to go away is easy enough, but assigning id what = self seems like it would not solve the problem.
EDIT: as I realized quite late in this question, the real problem here was that I am rescheduling from within the block itself. This is obviously problematic, because each block retains the next.
NOTE: I am aware that there are lots of questions on this topic, but I'm not expert enough to know which, if any, situations are similar to this one.
- (void) scheduleControlSurfaceProcess {
__weak id SELF = self;
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
id strongSelf = SELF; //Guarantee self doesn't go away in the meantime
// do something
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
[strongSelf scheduleControlSurfaceProcess];
}];
}];
}
That would guarantee you won't have a cycle here. The warning is completely valid, self retains the operation queue, the queue retains the block, the block retains self. And round and round we go.
In my modified example the block will capture SELF and store it into 'strongSelf'. The strongSelf step isn't strictly necessary, but it will make sure the reference to self doesn't get niled during execution of the block.

Resources