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

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.

Related

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.

NSOperationQueue and Memory

I've been using an NSOperationQueue and I have very strange memory issue with it.
I've tried reducing the issue to the simplest possible probleme and here I got:
in init:
_queue = [[NSOperationQueue alloc] init];
Later:
TestOperation op = [[TestOperation alloc] init];
[self.queue addOperation: op];
then in the method called by the main of the operation:
NSLog(#"I'm right here!");
If I call this thousands of times, my memory used just keep growing.
I've I only remove the NSLog from my method (thus calling an empty method) my memory don't change.
What am I doing wrong here??
When you add an operation to an NSOperationQueue, the operation queue owns the object and will be responsible of releasing it. Perhaps you are not giving enough time to the NSOperationQueue to release the memory and see the results?
For this cases you can surrounded it with an #autorelease block, but since the operation queue is the one responsible for the release of the objects I don't know if it will work. Is worth a try.

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.

block is likely to lead a retain cycle [duplicate]

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

Resources