Nested blocks and references to self - objective-c

I have a block wherein I use self so I declare a weak reference to self:
__weak MyClass *weakSelf = self;
Now my questions:
I get an error where I define weakSelf and I don't understand what this should mean.:
weak attribute can not be specified on an automatic variable
Inside my block I pass weakSelf to another block and I am not sure if I now have to do the same thing again like so:
__weak MyClass *weakWeakSelf = weakSelf;
And then pass weakWeakSelf to that block?

This is most likely occurring as you are targeting down to iOS 4. You should change it to be
__unsafe_unretained MyClass *weakWeakSelf = weakSelf;

With ARC
__weak __typeof__(self) wself = self;
Wihtout ARC
__unsafe_unretained __typeof__(self) wself = self;

With libextobjc it will be readable and easy:
- (void)doStuff
{
#weakify(self);
// __weak __typeof__(self) self_weak_ = self;
[self doSomeAsyncStuff:^{
#strongify(self);
// __strong __typeof__(self) self = self_weak_;
// now you don't run the risk of self being deallocated
// whilst doing stuff inside this block
// But there's a chance that self was already deallocated, so
// you could want to check if self == nil
[self doSomeAwesomeStuff];
[self doSomeOtherAsyncStuff:^{
#strongify(self);
// __strong __typeof__(self) self = self_weak_;
// now you don't run the risk of self being deallocated
// whilst doing stuff inside this block
// Again, there's a chance that self was already deallocated, so
// you could want to check if self == nil
[self doSomeAwesomeStuff];
}];
}];
}

Related

Using method with self inside blocks

I need to execute same bunch of code in two blocks (I'm using ARC):
__weak typeof(self) weakSelf = self;
[_dataProvider doA:^(NSError *error) {
[weakSelf handleError:error];
}];
And in a different place i call:
__weak typeof(self) weakSelf = self;
[_dataProvider doB:^(NSError *error) {
[weakSelf handleError:error];
}];
Then I have my handler:
- (void)handleError:(NSError *)error {
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
Is it save to use it this way? Please do notice that handleError: method uses self inside. If not, then what is the proper approach here? BTW: self is a viewController and can be dealloced (doB: and doA: blocks are based on networking, so can be slow).
It is not safe to do this, even if many people a doing it like this.
You should use the "weakSelf" pattern with blocks when it is justified.
In your example the "weakSelf" pattern is not justified, because self don't have any strong reference to your block. You can use like this :
[_dataProvider doA:^(NSError *error) {
// here you can use self, because you don't have any strong reference to your block
[weakSelf handleError:error];
}];
Use "weakSelf" pattern if you have a strong reference to your block ( with a property or an instance variable for example) and your are capturing self inside the block, example :
#property(strong) void(^)(void) completionBlock;
....
__weak typeof(self) weakSelf = self;
self.completionBlock = ^{
// Don't use "self" here, it will be captured by the block and a retain cycle will be created
// But if we use "weakSelf" here many times, it risques that it will be nil at the end of the block
// You should create an othere strong reference to the "weakSelf"
__strong typeof(self) strongSelf = weakSelf;
// here you use strongSelf ( and not "weakSelf" and especially not "self")
};

What happens to weakSelf and strongSelf in a block when the same block is executed multiple times?

PREFACE
According to the Clang docs, "For __weak objects, the current pointee is retained and then released at the end of the current full-expression." Which to me indicates that if I do this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
[weakSelf doSomethingInBlock];
}
}];
NOTE
If you reference #dasblinkenlight's answer below, you'll notice that there is a possibility of weakSelf becoming nil before doSomethingBlock.
Assuming doSomethingInBlock, does start with weakSelf existing, the rest of it should run no problem and there's no risk of weakSelf becoming nil before it has finished executing. However, if I were to run this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
if (weakSelf) {
// Guaranteed to be retained for scope of expression
[weakSelf doSomethingInBlock];
// weakSelf could possibly be nil before reaching this point
[weakSelf doSomethingElseInBlock];
}
}];
The work around that is suggested is to take weakSelf and convert it to a strong variable inside of the block, like this:
__weak typeof(self) weakSelf = self;
[self doSomethingInBackgroundWithBlock:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[strongSelf doSomethingInBlock];
[strongSelf doSomethingElseInBlock];
}
}];
QUESTION
What happens to the weakSelf and strongSelf during multiple iterations of the same block? Is there a chance that in processBlock()(below), self could exist for some objects and not for others?
EXAMPLE
For example, if I were processing an array of objects in the background using something like this, where processBlock contains references to self:
- (void) processValuesInBackgroundWithArray:(NSArray *)array usingBlock:(void (^)(id))processBlock {
for (id ob in array) {
// Block is called for each Object
// Is there a chance that self will exist for some objects and not for others?
processBlock(ob);
}
}
Called like this:
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
So the block references strongSelf from weakSelf, but the block is executed multiple times. Is there a chance that strongSelf might become nil in between iterations of objects in an array?
There is no guarantee that in your first example the weakSelf inside the if would be non-nil, because the block has two full expressions that reference it:
the if (weakSelf) check is the first full expression
the weakSelf in [weakSelf doSomethingInBlock]; invocation is the second one.
Therefore, your trick with strongSelf should be applied even when there is only one weakSelf invocation "protected" by the if statement.
Is there a chance that in processBlock()(below), self could exist for some objects and not for others?
Since there is no guaranteed __strong reference in a stack frame preceding the processValuesInBackgroundWithArray: call, self may become released between iterations of the loop, but only in a situation when the call of your last code snippet happens on a __weak or an unretained reference to the object containing the method from your last snippet.
Let's say that your last code snippet is inside a method called testWeak, in a class called MyClass:
-(void)testWeak {
__weak typeof(self) weakSelf = self;
[self processValuesInBackgroundWithArray:someArray usingBlock:^(id object) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
[self doSomethingWithObject:object];
[self doSomethingElseWithObject:object];
}
}];
}
When the call is made like this
[myClassObj testWeak];
and myClassObj is __strong, the self object inside testWeak would be retained outside the call by the strong reference to myClassObj, so your code would be good, with or without the strongSelf trick.
When myClassObj is weak, however, and the last __strong reference gets released concurrently with the running loop, some objects inside the loop would end up seeing a nil weakSelf inside the block. The only difference that the strongSelf is going to make is preventing that doSomethingElseWithObject would be called on nil, while doSomethingWithObject would be called on a non-nil object.

Blocks with reference to self and instance vars

What's the correct way to reference 'self' (and ivars) within blocks without the block creating a strong reference (and thus incrementing the ref count)?
For instance, I've found the following increments the ref count for 'self':
^(id sender) {
[self.navigationController popViewControllerAnimated:YES];
}
In order to circumvent the above, I've been doing the following:
__weak WhateverController *weakSelf = self;
^(id sender) {
[weakSelf.navigationController popViewControllerAnimated:YES];
};
And yes, I realize this is pseudocode.
Also, an indirect reference to self also creates a retain on self. For example, if _ivar were an instance variable, accessing it is an implicit reference to self so the following would also retain self.
^(id sender) {
[_ivar popViewControllerAnimated:YES];
}
Furthermore, to expand on your weak example, it is OK to send a message to a weak reference. If it's nil, nothing will happen. If not, then the compiler will generate code that ensures the reference remains valid through the invocation of the method.
So, this is fine:
__weak Foo *weakSelf = self;
^(id sender) {
[weakSelf.foo doSomething];
}
because foo will either be nil or if not, it is guaranteed to remain non-nil throughout the execution of doSomething.
However, the following would be inadvisable because self could go to nil in-between calls, which is probably not what you want:
__weak Foo *weakSelf = self;
^(id sender) {
[weakSelf.foo doSomething];
[weakSelf.foo doSomethingElse];
}
In that case, you probably want to create your own strong reference inside the block, so you have a consistent value throughout the execution of the block.
On the other hand, if you access iVars directly through a weak reference, you must do the weak-strong dance because this code:
__weak Foo *weakSelf = self;
^(id sender) {
weakSelf->_foo = bar;
}
will blow up if weakSelf is nil.
Thus, in the last two situations above, you want to do something like:
__weak Foo *weakSelf = self;
^(id sender) {
Foo *strongSelf = weakSelf;
if (!strongSelf) return;
// Now, do anything with strongSelf, as it is guaranteed to be around
}
Of course, the iVar situation is only a problem if you actually access iVars directly...
Apple's notation is sself but other than that - you're fine.
In a non arc project use the following code to prevent 'self' from being retained by the block:
__block id sself = self

Block that can access self and be used throughout an instance

I want a block that is available throughout a class, so it can be re-used many times by different methods in the instance.
I want that block to be able to reference self.
I want to not have the block create any nasty retain cycles by retaining self.
So far I am stumped. I managed to create block in the .m outside of any method definitions, and that got me partway - I could reuse the block everywhere, but I couldn't access self. I tried putting the block into an ivar but I'm doing something wrong there and now I'm getting random EXC_BAD_ACCESS. Can someone explain it simply, line by line?
Try the following:
typedef void (^MyBlock)();
#implementation MyClass
{
MyBlock block;
}
- (id) init
{
self = [super init];
if (!self)
return nil;
__block MyClass* _self = self;
block = [^ {
[_self sendSomeMsg];
} copy];
}
Note the __block storage type. Quoting this: "At function level are __block variables. These are mutable within the block (and the enclosing scope) and are preserved if any referencing block is copied to the heap."
This idiom may help you to remove the exc_bad_access (ARC code).
// get a weak reference to self
__weak id weakSelf = self;
block = ^()
{
// now the block is executing so we get a strong reference to self
// (this prevents self from disappearing until the block is done executing)
id strongSelf = weakSelf;
if (strongSelf != nil)
{
// do whatever work you intended for this block
}
};
I figured it out.
In MyClass.h:
typedef void (^DefaultFailureBlock)();
#property (copy) DefaultFailureBlock defaultFailureBlock;
in the init method:
__block MyClass *selfReq = self;
self.defaultFailureBlock = ^{
//use selfReq instead of self in here.
};
Interestingly, if you accidentally refer to self inside the block, you will have a retain cycle, and Analyze will not complain. I put an NSLog in dealloc to prove that it is actually being dealloced, and it is.
Oh and don't forget to [defaultFailureBlock release]; in dealloc too...

Problem with releasing an object

I've got this code:
Entry.h
#import <Foundation/Foundation.h>
#interface Entry : NSObject {
id object;
SEL function;
}
#property (retain) id object;
#property (assign) SEL function;
-(Entry*) initWithObject:(id)object selector:(SEL)function;
#end
Entry.m
#import "Entry.h"
#implementation Entry
#synthesize object;
#synthesize function;
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
[self setObject:obj];
[self setFunction:sel];
return self;
}
-(void) dealloc {
[super dealloc];
if ([self object] != nil)
[[self object] release];
}
#end
And when I do this:
Entry *hej = [Entry alloc];
[hej release];
I get:
objc[2504]: FREED(id): message object sent to freed object=0xf5ecd0
Program received signal: “EXC_BAD_INSTRUCTION”.
What am I doing wrong?
(And this insert code thing at stack overflow doesnt work, unless I'm doing something wrong and you're not supposed to click "code sample" and then paste.)
+alloc only allocates memory. You need -init to actually create the object in that memory space. Since you are only allocating memory and not creating an object there, calling -release on a chunk of memory is giving you an error. Further, you want your [super dealloc] call to appear at the end of you -dealloc method. Change those two things and the following should work:
Entry *hej = [[Entry alloc] init];
[hej release];
there are two problems here:
1) you need to check that self = [super init] does not return nil. Typical usage would be to follow wrap your initialization code with the conditional:
if ((self = [super init]) != nil) {
// initialize the object...
}
2) but where you are getting stuck is on instantiating your object: you should do it like this:
Entry *hej = [[Entry alloc] initWithObject:myObj selector:mySelector];
(assuming that you want to go through the custom initializer you just defined...
else just use the default init method.) but 'alloc' must be followed by an init.
Entry *hej = [[Entry alloc] init]; // will do the trick...
Firstly, you need an init to go with your alloc. Second, in dealloc, you send a message to self after calling [super dealloc]. You can't do that. The final deallocation should go at the end.
I would also recommend changing:
if ([self object] != nil)
[[self object] release];
to:
[self setObject:nil];
It's less code and functionally equivalent. =)
There are many things wrong with your code. I'll try to go through them.
First, its better to use a different ivar name to your property name so its clear where you are using each. Apple normally uses an underscore prefix, but any prefix will do.
#interface Entry : NSObject {
id _object;
SEL _function;
}
#property (retain) id object;
#property (assign) SEL function;
#synthesize object = _object;
#synthesize function = _function;
Next, you aren't using the standard init template (although this probably wont make any difference normally).
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
if (self != nil) {
// initializations
}
return self;
}
Next, Apple (for good reasons) recommends against using getters/setters in your init/dealloc. So your init would be:
-(Entry*) initWithObject:(id)obj selector:(SEL)sel {
self = [super init];
if (self != nil) {
_object = [obj retain];
_object = sel;
}
return self;
}
Next, after [super dealloc] your object is destroyed, so you cannot reference self (and hence your ivars) after that, so your dealloc should look like:
-(void) dealloc {
// your deallocations
[super dealloc];
}
Further, as above, Apple recommends you should not use setters or getters in your dealloc routine, so your deallocation would initially look like:
if (_object != nil)
[_object release];
But further still, Objective C allows (and Cocoa encourages) that sending a method to nil does nothing. This is in stark contast to most other languages where messaging nil would cause a crash, but it is how Objective C/Cocoa work and you need to get used to it. So your deallocation is actually just:
[_object release];
And finally, alloc only allocates the memory for your object, you have to initialize it, so the initialization would be something like:
Entry *hej = [[Entry alloc] initWithObject:myobj selector:#selector(mymethod)];