I noticed Apple's documentation saying we need to avoid strong reference cycles when capturing self.
The block in the example is a property of self.
But what if I put a block as a local variable in a dispatch_async statement?
In this case, it will not create a retain cycle even if I directly call a method of self, right?
Is the following code generating weakSelf required in this article?
// your code
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doThis];
[strongSelf doThat];
[Manager.sharedInstance updateSuccessCount];
}
});
// more code
In the example given, using dispatch_async, there would be no retain cycle, so it would be safe to capture self strongly here. The only difference would be that if self were released by everything else between when this dispatch_async was called and when the block actually ran, it would slightly delay the actual deallocation of self for that brief time, and could affect which thread the deallocation actually occurs on as well. But in general there's no harm in doing it either way when using dispatch_async.
One case where you may want to do it the way your example is written above is if the code run in the block is somewhat expensive and would only want to be done if absolutely necessary, and that it's unnecessary if self had already been released by everything else.
Another case may be if self uses a large amount of memory and gets deallocated normally right before something else starts consuming a lot of memory. In that case you may not want those two instances to be allocated at the same time.
Related
I know that when we use block we should use weakSelf to avoid retain cycle.But I saw there is a strongSelf in block sometimes.
What confused me are:
why must change weakSelf to strongSelf?
if we don't change weakSelf to strongSelf what terrible thing would happen?
when should we change weakSelf to strongSelf?
Hope someone can give an exact example.
Thanks in advance.
why must change weakSelf to strongSelf?
Sometimes you want your block to NOT execute if the reference to self is already nil (user dismissed the view). This is why you first use weak references. (COMMON CASE)
However, sometimes you want your block to finish executing ensuring all the things its referencing are alive, but only if "self" is still alive once the block has started. In this case you make the block convert the weak reference into strong. (RARE CASE)
if we don't change weakSelf to strongSelf what terrible thing would happen?
If the block started executing while self is alive (allowing it to begin) but gets deallocated in the middle of the processing (think of a time consuming function such as image processing), and then the block accesses a resource from self (which no longer exists) it will crash.
when should we change weakSelf to strongSelf?
Almost never. The only example I can think of is when your block absolutely needs the resources from "self" once it has begun executing.
There's a more detailed explanation in this answer:
Strong reference in the block, it will be retained?
The only reason to capture self, as a weak or strong reference, in a block is because the block uses it in some way.
When self has been captured weakly how it is used will determine when, and if, you need to make a strong copy first.
If the block is going to use the captured reference multiple times then a strong copy should always be made, this insures the reference stays alive across all the uses within the block and avoids the cost of loading a weak reference multiple times.
For example, if the block's function is dependent on whether self still exists then it would be usual to start by making a strong reference and testing it. Something along the lines of:
__weak __typeof(self)weakSelf = self;
myBlock = ^{
// make local strong reference to self
__typeof(weakSelf) strongSelf = weakSelf;
// check if self still exists and process accordingly
if (strongSelf)
{
// do whatever is needed if "self" still exists
// strongSelf will keep the object alive for the
// duration of the call
}
else
{
// do whatever, if anything, is needed if "self" no longer exists
}
});
However if the block's operation only optionally requires the use of the object referenced by self then a strong copy may never be made.
HTH
In any case you need the "self" after the callback return - it is never wrong to turn weak self to strong self, in worst case - just extra code. but the opposite is not true.
here is a very simple example where you indeed need a strong ref.
__weak typeof(self) weakSelf = self;
[self.bgQueue1 addOperationWithBlock:^{
[weakSelf doSomeMagic:weakSelf.importentArr arg:number];
if (weakSelf.importentArr.count == 10){
//we will have crash(or other unpredictable results) if weakSelf will turns to nil
[DataBaseClass save:weakSelf.importentArr];
}
}];
I have this loop that has this NSDictionary. Every turn, this NSDictionary is created with new values. The problem is that this loop fires an async block to be executed. Something like:
for (int i=0; i<10; i++) {
NSDictionary *aDict = [self fillDictWithCurrentValues];
dispatch_async(dispatch_get_main_queue(), ^{
executeBlock(aDict);
});
}
My problem is this. I want this block to execute with the dictionary passed to it but because the loop will execute faster, it will go out of scope when executeBlock runs. So, two questions:
I suspect every block will hold a reference to its correspondent aDict, so they will not crash even if they execute when the caller is out of scope, right?
aDict is a strong reference. Do I need to create a __weak version before calling the dispatch_async and a __strong reference inside the dispatch_async so there is no retain cycle?
You ask:
I suspect every block will hold a reference to its corresponding aDict, so they will not crash even if they execute when the caller is out of scope, right?
It will keep strong reference while the block runs, so you don't have to worry about it being deallocated on you.
That having been said, there is a question of what fillDictWithCurrentValues does. If it's creating a new dictionary each time, you're fine. But if it's returning some reference to some dictionary that is shared, this can be problematic. It just depends upon what this method is doing.
aDict is a strong reference. Do I need to create a __weak version before calling the dispatch_async and a __strong reference inside the dispatch_async so there is no retain cycle?
There's no strong reference cycle because when dispatch_async is done running the block, the block will be released.
You might still use the weakSelf pattern if (a) there's a possibility that self might be deallocated before the closures are done running; and (b) you think it's important that the closures don't prevent that from happening. But usually, when dispatching updates back to the main queue (which you only do with very fast routines), you don't worry about it.
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?
This question already has answers here:
How does the new automatic reference counting mechanism work?
(6 answers)
Closed 9 years ago.
I'm new to Objective C and I'm porting parts of an old (non ARC) framework to ARC. My question is, although ARC handles a lot of memory management behind the scenes now, are there any major memory management principles that I still need to be aware of to avoid leaks?
For instance I thought I read somewhere that in the 'main' function of an NSOperation subclass, the programmer should set up an 'autoreleasepool' for that function.
Probably the two biggest issues to watch for are 1) retain cycles, where x retains y and y retains x thus they're never freed. This usually happens with blocks. And 2) when using Core Foundation functions (Core Graphics etc), for example: CGImageCreate, CGImageRetain, CGImageRelease. You still need to manually manage the memory in those cases.
A common pattern to prevent retain cycles is to create a weak reference to one of the objects that would be in the cycle. (Often self). Such as this:
__weak typeof(self) weakSelf = self;
[self useBlock:^{
typeof(weakSelf) strongSelf = weakSelf;
// do something with strongSelf
}];
Notes:
a) The reason you want to create a new strongSelf inside the block, is to ensure you're retaining the weakSelf variable for the duration of the block. Otherwise, you can have cases where weakSelf will become nil part way through the block. In some cases, you may want to add a test that strongSelf still exists immediately, and if not abort the block altogether. As weakSelf could become nil before the block starts.
__weak typeof(self) weakSelf = self;
[self useBlock:^{
typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// do something with strongSelf
}];
b) You only need to do this when self will be retaining the block (in this case via something the unknown useBlock method is doing).
The programmer still needs to be 100% aware of retain/release, however, the compiler is doing 98% of the work. The 2% it can't do well is breaking retain cycle's, so it's helpful for the compiler to specify weak retention in properties or using the __weak modifier in select scenarios.
You may still setup your own #autoreleasepool's, too. The only time I've used them purposefully is in/as the body of a for loop, to force the memory to be reclaimed each iteration.
Examine the following code, and assume it was compiled under ARC:
- (void)foo {
NSOperationQueue *oq = [[NSOperationQueue alloc] init];
[oq addOperationWithBlock:^{
// Pretend that we have a long-running operation here.
}];
}
Although the operation queue is declared as a local variable, its lifetime continues beyond the scope of the method as long as it has running operations.
How is this achieved?
UPDATE:
I appreciate Rob Mayoff's well-thought-out comments, but I think I did not ask my question correctly. I am not asking a specific question about NSOperationQueue, but rather a general question about object lifetime in ARC. Specifically, my question is this:
How, under ARC, can an object participate in the management of its own lifetime?
I've been a programmer for a very long time, and I'm well aware of the pitfalls of such a thing. I am not looking to be lectured as to whether this is a good or bad idea. I think in general it is a bad one. Rather, my question is academic: Whether it's a good or bad idea or not, how would one do this in ARC and what is the specific syntax to do so?
As a general case you can keep a reference to yourself. E.g.:
#implementation MasterOfMyOwnDestiny
{
MasterOfMyOwnDestiny *alsoMe;
}
- (void) lifeIsGood
{
alsoMe = self;
}
- (void) woeIsMe
{
alsoMe = nil;
}
...
#end
Here are a few possibilities:
The NSOperationQueue retains itself until it is empty, then releases itself.
The NSOperationQueue causes some other object to retain it. For example, since NSOperationQueue uses GCD, perhaps addOperationWithBlock: looks something like this:
- (void)addOperationWithBlock:(void (^)(void))block {
void (^wrapperBlock)(void) = ^{
block();
[self executeNextBlock];
};
if (self.isCurrentlyExecuting) {
[self.queuedBlocks addObject:wrapperBlock];
} else {
self.isCurrentlyExecuting = YES;
dispatch_async(self.dispatchQueue, wrapperBlock);
}
}
In that code, the wrapperBlock contains a strong reference to the NSOperationQueue, so (assuming ARC), it retains the NSOperationQueue. (The real addOperationWithBlock: is more complex than this, because it is thread-safe and supports executing multiple blocks concurrently.)
The NSOperationQueue doesn't live past the scope of your foo method. Maybe by the time addOperationWithBlock: returns, your long-running block has already been submitted to a GCD queue. Since you don't keep a strong reference to oq, there is no reason why oq shouldn't be deallocated.
In the example code give, under ARC, the NSOperationQueue, being local to the enclosing lexical scope of the block, is captured is captured by the block. Basically, the block saves the value of the pointer so it can be accessed from within the block later. This actually happens regardless of whether you're using ARC or not; the difference is that under ARC, object variables are automatically retained and released as the block is copied and released.
The section "Object and Block Variables" in the Blocks Programming Topics guide is a good reference for this stuff.
The simplest thing I can think of would be to have a global NSMutableArray (or set, or whatever) that the object adds itself to and removes itself from. Another idea would be to put the (as you've already admitted) oddly-memory-managed code in a category in a non-ARC file and just use -retain and -release directly.