Always Pass Weak Reference of Self into Block in Arc

Always pass weak reference of self into block in ARC?

It helps not to focus on the strong or weak part of the discussion. Instead focus on the cycle part.

A retain cycle is a loop that happens when Object A retains Object B, and Object B retains Object A. In that situation, if either object is released:

  • Object A won't be deallocated because Object B holds a reference to it.
  • But Object B won't ever be deallocated as long as Object A has a reference to it.
  • But Object A will never be deallocated because Object B holds a reference to it.
  • ad infinitum

Thus, those two objects will just hang around in memory for the life of the program even though they should, if everything were working properly, be deallocated.

So, what we're worried about is retain cycles, and there's nothing about blocks in and of themselves that create these cycles. This isn't a problem, for example:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];

The block retains self, but self doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.

Where you get into trouble is something like:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];

Now, your object (self) has an explicit strong reference to the block. And the block has an implicit strong reference to self. That's a cycle, and now neither object will be deallocated properly.

Because, in a situation like this, self by definition already has a strong reference to the block, it's usually easiest to resolve by making an explicitly weak reference to self for the block to use:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];

But this should not be the default pattern you follow when dealing with blocks that call self! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after self was deallocated.

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];

Why passing a weak reference to a block prevents an object from being retained?

You can sort of think of a block as an object which has an "instance variable" for each captured variable, which is initialized with the value of the corresponding captured variable at the time the block is created.

In ARC, the block's "instance variables" have the same ownership specifier as the corresponding captured variable. So if a captured variable of object-pointer type is __strong (the default), the block's "instance variable" is also __strong, so it retains the object pointed to for the lifetime of the block. If a captured variable of object-pointer type is __strong, the block's "instance variable" is also __weak, hence it is a zeroing weak reference to the object pointed to.

Disappearing reference to self in a block under ARC

Here is essentially what your code is doing:

  1. Making a weak variable, weakSelf.
  2. Passing a block to a function that references that weak variable.

A this point, self is not retained by the block nor the weakSelf variable. Then, when the block runs, weakSelf is put into a __strong variable, thus retaining any value that was in weakSelf. Unfortunately, if the original value of weakSelf, namely self was already deallocated, weakSelf would be nil already.

The compiler can see what external variables your block accesses, and then adds any necessary retains if those variables are __strong. The compiler does not care that you assign a __weak variable to an internal variable that happens to be __strong. This retain will happen when the block runs, not when it is created.

By using self directly from the block, the compiler sees that you are referencing a variable that is not __weak, and therefore automatically retains that variable for the lifecycle of the block. In cases like this, I see no reason why you wouldn't directly reference self in the block, unless you are worried about a circular retain cycle.

Weak Self in Blocks

That check is unnecessary, and is giving you a false sense of security.

Here's the problem:

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (!weakSelf) { return; }
// THE LINE OF INTEREST
[weakSelf doSomething];
});

At THE LINE OF INTEREST, some other thread might clear the last strong reference to self, at which point weakSelf is set to nil. So the doSomething message gets sent to nil, which is “safe” (it does nothing), but might not be what you expected!

It's worse if you want to take a different action when weakSelf is nil, e.g.

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
if (weakSelf) {
[weakSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});

In this case, between the time the block verifies that weakSelf is not nil and the time it sends the doSomething message, weakSelf might become nil, and neither doSomething nor doSomethingElse will actually run.

The correct solution is this:

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomething];
} else {
[someOtherObject doSomethingElse];
}
});

In this case, copying weakSelf to strongSelf (which is strong by default) is atomic. If weakSelf was nil, strongSelf will be nil. If weakSelf was not nil, strongSelf will not be nil, and will be a strong reference to the object, preventing it from being deallocated before the doSomething message.

Does a reference remain weak if passed as an argument in objective-c?

It is the variable weakSelf which is weak. That is, ARC does not emit a retain when a value is assigned to it, nor a release when it goes out of scope (or is assigned a different value).

Since the fooDelegate property is strong, assigning to it releases any old value it may have had and retains the newly-assigned value.

So, yes, that will be a strong reference. It's not clear from what you posted whether it will constitute a retain cycle. The name of the method suggests that the delegate will be cleared (thus released) after the work has been completed. In that case, it's not a problem. It would only be a problem if self.someObject maintained the strong reference until it itself was released and self maintained a strong reference to someObject until self was released.

Weak self vs self when using closure defined in swift in objective c

First of all try to understand what is a retaincycle and how it will affect your application..

A retain cycle is a condition that happens when two objects keeps strong reference to each others.

Sample Image

In such cases these objects won't get deallocated and it will stay in memory forever and leads to memory leak.

Retain cycle in blocks and why should we use weakself

Closures and blocks are independent memory objects and they will retain the objects they reference so if we are accessing any class variable or method inside the closure or block using self then there is a chance for retain cycle

self.myBlock = ^{ self.someProperty = xyz; }; // RETAIN CYCLE

will get this warning

Capturing 'self' strongly in this block is likely to lead to a retain
cycle

To avoid such situation we should weakSelf to access members

__weak typeof(self) weakSelf = self;

`self.myBlock = ^{ weakSelf.someProperty = xyz; };`

So there is a rule like always use weakSelf in blocks but there are some special cases like animation blocks

[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }];

Here we can use self inside the block because the blocks get destroyed automatically once animation completed.

Is it necessary to use weak references to self always inside blocks..?

You should only use a weak reference to self, if self will hold on to a reference of the block.

In your example, you are not keeping a reference to your block in self, you are only using blocks inline with the UIView animateWithDuration:, and as such there is no need to use __weak myViewController *weakSelf = self;

Why is this the case? Because a block will retain strong references to any variables it uses from the class using the block. This includes self. Now if the class instance itself keeps a strong reference to the block, and the block keeps a strong reference to the class instance, you have a retain cycle, which will cause memory leaks.

In Objective-c blocks, do I need to pass weak/strong self to helpers?

TLDR

When to use strong or weak depends on how you use the block. In your code strong and weak does not really matter but I will give an example where it matters and explain how to then use weak.

I think you are considering the wrong things here. In your example all pointers to self can (and should) be strong. You do not need to dance the dance here and you should consider using weak only when you create retain cycles which I will discuss in a moment.

In your case note that when you are inside the block you want a strong pointer to self. If you have a weak pointer the block becomes superfluous when self is nil. To get a strong pointer simply change your block to

... ^{
[self _privateHelper];
});

rather than the way you do it. Now (and in your original code) you have (and should have) a strong pointer to self inside both your _privateHelper and _secondPrivateHelper.

But this is not the issue.

Retain cycle

Suppose you have an ivar

@property (strong,nonatomic) void ( ^ block )( void );

Only now do you have potential trouble and you probably need to use weak pointers. The reason being that if somewhere in your code you have

self.block = ^{ [self _privateHelper]; };

the block will retain a strong pointer to self. At the same time, self is keeping, through the ivar, a strong pointer on the block. Can you see the retain cycle? Neither the block nor self will ever be released automatically as both are keeping strong references to the other.

Fixing it

You can change the ivar to weak in which case you break the cycle. If the block goes out of scope the weak ivar goes to nil and there is no retain on self.

You could also do

self.block = ^ { [weakSelf _privateHelper]; };

inside the block to break the cycle. Now if self goes out of scope the block no longer has a hold on it and again there is no retain cycle on self.

Both these fixes are used - a lot of ivars will be weak in a UI environment to prevent the e.g. label keeping a strong reference on the vc while the vc also keeps a strong reference on the label.

When working with blocks you typically use weak pointers to self inside the block only if you potentially have a retain cycle. This is often not an issue and in your code also is not an issue as self does not retain the block. So in general your helper blocks could probably get away with strong pointers to self. You only need to dance the dance if somehow self and the block are creating a retain cycle.

Finally, a third way to fix it is to set the ivar to nil yourself. So you could have code that looks like this

if ( self.block )
{
self.block (); // Execute block
self.block = nil;
}

This also makes sense sometimes e.g. when you want to retain the block and self until the block executes. Here you release the ivar manually by setting it to nil after which it no longer retains self and the cycle is broken albeit manually.

You could even do this inside the block, e.g. change the block to

self.block = ^ { [self _privateHelper]; self.block = nil; /* release when done */ };

Does [self new] in a block creates strong reference cycle?

Will [self new] act like [MyType new] or a block will capture self?

As mentioned by the other answers, this is no retain cycle. However, keep in mind that self points to the class object and class objects are not object of ARC: They have an eternal life time.

Is it a right way to create new instance of MyType using [self new]?

It is the better way. See below.

What are benefits of using [self new] instead of [MyType new]?

Inside the implementation of the class you should almost always use self instead of MyType. (But your code is one of the rare examples for having no advantage of doing so because of the static variable.)

The reason for this is, that code can be used by subclasses. If you put the concrete type in your code, every creation method has to be overwritten, which can lead to much code and triggers the broken base class problem.

Example:

@implementation BaseClass
+ (instancetype)new…
{
BaseClass *instance = [BaseClass new];

}
@end

@interfac Subclass : BaseClass

@end

This is broken, because …

id instance = [Subclass new…];

… would create an instance of the subclass.

You have to overwrite new…, what has an additional problem:

@implementation Subclass
+(instancetype)new…
{
/* Subclass *instance = [super new]; Does NOT work*/
… Complete re-implementation of +new… (BaseClass)
}

Block in block, with __weak self

In this case (below) use just strong self, because the block is copied just for those few seconds. And usually if you want the self to perform block, you want to it to stay alive until that time, so strong reference is perfectly okay.

[self performBlock:^{
[self doSomething]; // strong is OK
} afterDelay:delay];

Block inside a block? In your case those two block are just delayed one-shot blocks, so the same as above, use strong. But there are differences between blocks. If you store the block for longer time, maybe for multiple invocations you should avoid retain-cycles.

Example:

self.callback = ^{
[self doSomething]; // should use weakSelf
};

This may cause retain-cycle. In fact it depends on how the block is used. We see that the block is stored (copied) in property for later use. However, you can prevent the retain-cycles by nullifying block that will not be used any more. In this case:

self.callback(); //invoke
self.callback = nil; //release

When using ARC, you don't have to copy blocks yourself. There were bugs in early versions after blocks were added, but now the compiler under ARC knows when to copy blocks. It is clever enough to copy it in this case:

[self performSelector:@selector(executeBlockAfterDelay:) withObject:block afterDelay:delay];


Related Topics



Leave a reply



Submit