Purposely Create Retain Cycle (Objective C without GC) - objective-c

Is there ever a case where purposely creating a retain cycle to prevent deallocation, then cleaning it up later, is the best solution to a problem?
If so, are there examples of this in the Cocoa Touch or NextStep frameworks?
I intend this question to be specific to Objective C with ARC since Objective C with GC or other languages with GC may behave differently.

Sure. It's actually not all that uncommon, though you may not realize it.
For example, let's assume that my controller is making a network request, and I really need to make sure I handle the response, even if the user has navigated away from that controller.
I might do something like this:
- (void)doNetworkThing {
__block MyController *blockSelf = self;
NSURLRequest *request = // some request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error) {
// Handle the response here
[blockSelf doThingWithResponse:response];
}];
}
This introduces a trivial retain cycle where self has caused itself to be retained by assigning itself to the strong pointer blockSelf. Until blockSelf goes out of scope, self will not be deallocated.
Note that often, you would use a weak pointer in this situation. But if you really need the controller to be around to handle it, using a strong pointer works too. As soon as the handler block is deallocated, its reference to blockSelf will go away. Since the the stack reference to blockSelf is also gone self will then be deallocated if nobody else is holding on to it.
So basically, blockSelf caused a temporary retain cycle, which was useful in ensuring that deallocation could not happen until the request finished. Because ARC automatically cleans up the retain counts when the __block variable goes out of scope, it doesn't look much like a retain cycle. But nevertheless, that's what it is.

Sure, there are several. Most notably NSURLConnection generates a retain loop with its delegate to ensure that the delegate cannot go away before the connection completes. Somewhat less ideally, NSTimer generates a retain loop with its target. This unfortunately causes problems for repeating timers (see RNTimer for one of many attempts to work around this issue).
Generally speaking, if a delegating object has a very short lifespan compared to its delegate, it is natural for it to retain its delegate in order to create a beneficial retain loop.
It is much less common, but still done, for certain kinds of objects to "self retain." For example, if you had an object that you wanted to create and have some operation perform, and then destroy itself, then self retain can solve that problem. Typically it is better to avoid that and let the caller retain the object, but it still has its uses (I've used it for logging and other non-critical operations that I want to fire-and-forget).
That said, it is not uncommon in my code to intentionally create short-lived retain loops with blocks to ensure that the calling object cannot vanish before the block finishes.

Related

Is it necessary to use __strong in a completion block with __weak? [duplicate]

I think I understand strong and weak keywords well, but I don't understand how it's used in the code below. This code is from SDWebImage by Olivier Poitrey available on github. I understand strong and weak keywords as is described here: Explanation of strong and weak storage in iOS5
The code below uses __weak and __strong keywords in a way that is curious to me. It is not a child-parent relationship or delegate pattern as I am used to seeing weak used. However, I'm sure that this is a pattern that is used often, as I've seen it before in other code. It sets a __weak reference before a block that runs on another thread. Then, within the block, it sets the weak reference to a strong reference.
I am certain that this good and elegant code, so I'm trying to understand it. If "self" ceases to exist before the block runs, the weak self reference will zero out. When the block runs, the strong reference will be set to zero as well. Therefore, it will know to kill the rest of the operation since self doesn't exist anymore. Did I get this right?
Now, what would happen if we didn't use __weak and __strong keywords? What if we just checked inside the block whether self == nil. Would "self" never be nil since the block copies the entire tree?
Can someone help demystify this awesome piece of code? Can someone verify or repudiate my hypotheses?
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock;
{
[self cancelCurrentImageLoad];
self.image = placeholder;
if (url)
{
__weak UIImageView *wself = self;
id<SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
__strong UIImageView *sself = wself;
if (!sself) return;
if (image)
{
sself.image = image;
[sself setNeedsLayout];
}
if (completedBlock && finished)
{
completedBlock(image, error, cacheType);
}
}];
objc_setAssociatedObject(self, &operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
The downloadWithUrl: method might take a long time. In that time, the user might decide to navigate away, eliminating the need for the SDWebImage object. To facilitate early cleanup of the object, the outer self reference is weak. This way, downloadWithUrl won't prevent the SDWebImage from being deallocated.
Of course, if you actually want to work with self, you need a strong reference. So, the on-completion block of downloadWithUrl grabs a strong reference to self. If the object goes away in this time, sself will be nil. Otherwise, it will be a valid strong reference, indicating that the SDWebImage object is still around, and the object will finish its work at this time.
I am certain that this good and elegant code, so I'm trying to understand it. If "self" ceases to exist before the block runs, the weak self reference will zero out. When the block runs, the strong reference will be set to zero as well. Therefore, it will know to kill the rest of the operation since self doesn't exist anymore. Did I get this right?
Nope, you're over thinking this quite a bit. The __weak storage qualifier is just that: a qualifier. Objects that are __weak are explicitly unretained, but they aren't just automatically set to nil if assigned from a strong variable. In fact, that would defeat the purpose of a weak variable!
Now, what would happen if we didn't use __weak and __strong keywords? What if we just checked inside the block whether self == nil. Would "self" never be nil since the block copies the entire tree?
The checking is actually unnecessary because the runtime resolves messages to nil to nil (nevertheless, it may be important to the implementation later on, who knows). You are spot on with this one: without that little "weak to strong" dance there, then self would be retained by the block, with the potential to create a pretty nasty retain cycle. Which is where I can start tying this all together:
Because we don't want the block to retain our variable, but we also want it to be strong inside the scope of the block so nothing weird happens, self is assigned to a weak pointer. When the block happens upon our weak pointer, it isn't allowed to retain it, so self's reference count stays the same, then once inside the block, we go right back to a strong self variable so the weak one is released, and we don't have to worry about it any more. Practically, this means we have a solid guarantee that self is either a value or nil throughout the entire execution of the block. Pretty neat, huh?

Objective C memory management with blocks, ARC and non-ARC

I have been using blocks for some time now, but I feel that there are things I miss about memory management in both ARC and non-ARC environments. I feel that deeper understanding will make me void many memory leaks.
AFNetworking is my main use of Blocks in a particular application. Most of the time, inside a completion handler of an operation, I do something like "[self.myArray addObject]".
In both ARC and non-ARC enabled environments, "self" will be retained according to this article from Apple.
That means that whenever a completion block of an AFNetworking network operation is called, self is retained inside that block, and released when that block goes out of scope. I believe that this applies to both ARC and non-ARC. I have ran both the Leaks tool and the Static Analyzer so that I may find any memory leaks. None showed any.
However, it wasn't until recently that I stumbled upon a warning which I couldn't figure out. I am using ARC in this particular example.
I have two instance variables that indicate the completion and failure of a network operation
#property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
#property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
#synthesize failureBlock = _failureBlock;
#synthesize operation = _operation;
Somewhere in the code, I do this:
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
responseObject) {
NSError *error = [NSError errorWithDomain:#"com.test" code:100 userInfo:#{#"description": #"zero results"}];
_failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"nothing");
}];
Xcode complains about the line that calls the failureBlock, with the message "Capturing "self" strongly in this block is likely to result in a retain cycle. I believe Xcode is right: the failure block retains self, and self holds its own copy of the block, so none of the two will be deallocated.
However, I have the following questions/observations.
1) If i change _failureBlock(error) to "self.failureBlock(error)" (without quotes) the compiler stops complaining. Why is that? Is this a memory leak the compiler misses?
2) In general, what is the best practice to work with blocks in both ARC and non-ARC enabled environments when using blocks that are instance variables? Seems that in the case of completion and failure blocks in AFNetworking, those two blocks are not instance variables so they probably don't fall into the category of retain cycles that I described above. But when using progress blocks into AFNetworking, what can be done to avoid retain cycles like the one above?
I would love to hear other people's thoughts on ARC and non-ARC with blocks and issues/solutions with memory management. I find these situations error-prone and I feel some discussion on this is necessary to clear things up.
I don't know if it matters, but I use Xcode 4.4 with the latest LLVM.
1) If i change _failureBlock(error) to "self.failureBlock(error)"
(without quotes) the compiler stops complaining. Why is that? Is this
a memory leak the compiler misses?
The retain cycle exists in both cases. If you're targeting iOS 5+, you can pass in a weak reference to self:
__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError *error = [NSError errorWithDomain:#"com.test" code:100 userInfo:#{#"description": #"zero results"}];
if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"nothing");
}];
Now self won't be retained, and if it's deallocated before the callback is invoked, the callback is a no-op. However, it's possible that it could be undergoing deallocation while the callback is invoked on a background thread, so this pattern can create occasional crashes.
2) In general, what is the best practice to work with blocks in both
ARC and non-ARC enabled environments when using blocks that are
instance variables? Seems that in the case of completion and failure
blocks in AFNetworking, those two blocks are not instance variables so
they probably don't fall into the category of retain cycles that I
described above. But when using progress blocks into AFNetworking,
what can be done to avoid retain cycles like the one above?
Most of the time, I think it's better not to store blocks in instance variables. If you instead return the block from a method in your class, you'll still have a retain cycle, but it only exists from the time the method is invoked to the time the block is released. So it will prevent your instance from being deallocated during the block execution, but the retain cycle ends when the block is released:
-(SFCompletionBlock)completionBlock {
return ^(AFHTTPRequestOperation *operation , id responseObject ) {
[self doSomethingWithOperation:operation];
};
}
[self.operation setCompletionBlockWithSuccess:[self completionBlock]
failure:[self failureBlock]
];
That means that whenever a completion block of an AFNetworking network
operation is called, self is retained inside that block, and released
when that block goes out of scope.
No, self is retained by the block when the block is created. And it is released when the block is deallocated.
I believe Xcode is right: the failure block retains self, and self
holds its own copy of the block, so none of the two will be
deallocated.
The block in question that retains self is the completion block passed to setCompletionBlockWithSuccess. self does not hold a reference to this block. Rather, self.operation (presumably some kind of NSOperation) retains the blocks while it is executing. So there is temporarily a cycle. However, when the operation is done executing, the cycle will be broken.
1) If i change _failureBlock(error) to "self.failureBlock(error)"
(without quotes) the compiler stops complaining. Why is that? Is this
a memory leak the compiler misses?
There should be no difference. self is captured in both cases. The compiler is not guaranteed to catch all cases of retain cycles.

Object going out of scope, but delegate is set, using ARC

I'm so very sorry for the unclear title, but I can't explain it shortly.
I am basically wondering what happens if you use ARC and you have a method like this:
- (void)fooMethod:(NSURLRequest *)fooReq
{
NSURLConnection *fooConn = [NSURLConnection connectionWithRequest:fooReq delegate:self];
[fooConn start];
}
So fooConn goes out of scope at the end of the fooMethod, but will I still receive callbacks? In other words: because there aren't any more references, will it get dealloc'd (or something like that) immediately, or will it stay in memory and handle the request because the delegate is still set?
That totally depends on what NSURLConnection does behind the scenes. If the retain count drops to zero, then fooConn will be dealloc'ed still and one would assume no more callbacks would be made then.
Now, I think that NSURLConnection behind the scenes does get retained somewhere in the hierarchy of things so you would in fact receive callbacks. However with NSURLConnection I usually keep a strong reference to it lying around to be on the safe side. After all, you as the caller of it want to own it and you want to ensure that you will keep getting the delegate callbacks and not be at the mercy of whatever happens to it under the hood.
So, in short, if I were you I'd keep a strong reference to it to ensure you won't have to worry.
From the Apple docs:
- (id)initWithRequest:(NSURLRequest *)request delegate:(id < NSURLConnectionDelegate >)delegate startImmediately:(BOOL)startImmediately
The connection retains delegate. It releases delegate when the connection finishes loading, fails
fooConn is a local variable without any ownership qualifier so ARC will infer it as strong. Therefore ARC will retain the value returned by connectionWithRequest:delegate: when storing it into foxConn; and when exiting fooMethod: ARC will clean up by releasing fooConn.
That the delegate references the current instance will have no effect on this.
If you wish the NSURLConnection to exist after fooMethod: returns one way is to store it into an instance variable (which ARC also infers as strong, so no ownership qualifier required there either). If you do this when the class instance itself is no longer reference ARC will release the NSURLConnection.

Must I copy a block here?

I understand that you must copy blocks in order for them to stick around after a stack frame exits. But, how does that apply to stack-allocated blocks used within a nested block as in the following code example:
- doSomethingFunkyThenCall:(void(^)(int someValue))callback
{
[[NSOperationQueue currentQueue] addOperationWithBlock:^{
// ... do some work here, potentially nesting into further blocks ...
callback(result);
}];
}
Obviously, the doSomethingFunkyThenCall: stack frame will terminate before the callback is executed, so it will have to be copied. But will this happen automatically in the call to addOperationWithBlock: or do I have to do it manually?
Most likely, it will happen automatically. Cocoa's design principles imply in general that you're not responsible for objects (their memory management, passing blocks [which are, in fact, implemented as proper Objective-C objects], etc.) you haven't created. So you can just pass down the block you received as a parameter, and the runtime will manage it as per its needs.
Yes, you should do a callback = [[callback copy] autorelease]; at the top of this method.
Objects used in blocks are retained automatically, but sending a stack-block retain actually does nothing (because the semantics of retain require it to return the receiver), so will be gone once we leave the frame it was created in.
Sources:
http://cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html
http://thirdcog.eu/pwcblocks/#objcblocks
EDIT: It turns out I'm wrong. #bbum points out below that Block_copy will copy recursively, and since addOperationWithBlock: copies it's block, the callback is also copied.

Memory Management Autorelease vs. Alloc Question

3 correlated questions:
1.Do the code snippets below provide the very same results in terms of memory?
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
bundle=nil;
and
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSBundle *bundle=[NSBundle mainBundle];
[pool drain];
pool=nil;
bundle=nil;
2.Why in
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
the retainCount of bundle is 1, not 0?
3.Which is recommended: always use class methods, or always gain ownership by using alloc?
Thanks.
Yes, those should be equivalent in terms of memory management, from the developer's point of view. The frameworks might be doing something behind the scene to hang on to [NSBundle mainBundle], but that's not your concern.
Ignore retainCount. waves hand That's not the method you're looking for. Once you have relinquished ownership of an object, either by invoking release or autorelease, then it is invalid (bad practice) to send more messages to that object. In your example, you alloc an NSBundle, so you own it. That means it has a +1 retain count (I say +1, because it's relative). When you release the bundle, it now has a "0" retain count, which means you no longer own this object (despite whether or not it may still exist in memory), which means you should not send messages to it, under penalty of stuff blowing up in your face.
What's recommended is to use whatever's appropriate for the situation. If you just need a temporary object, then using a class method that returns an autoreleased object is probably going to be just fine. If you need to be absolutely sure that the object isn't going to go away while you're using it, then you can use an alloc/init approach (or retain an autoreleased object) and then just release it when you're done.
In the second example you will create 1 extra object (the NSAutorealeasePool) and because of that the two are not exactly the same in terms of memory. But after the code runs I believe the memory will return to the same state in both examples. I am not really sure but I believe that in the second example bundle is an autoreleased object, so when the pool is drained it gets released.
I believe that when the object gets dealloc'ed the retainCount isn't changed.
It is usually recommended to avoid class methods when you create a lot of temporary objects because they won't get released until the next AutoreleasePool drain is called (and if you don't have an AutoreleasePool inside your method it won't happen for sure until you return from your method - and maybe even later). Otherwise you should use the one that feels better for you. I personally prefer allocating them. It is also important to remember that if you want the autoreleased object (the one returned from a class method) to stick around even after you return from the function to retain it.