Blocks with reference to self and instance vars - objective-c

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

Related

Using an ivar inside a method which is called from a block

I want to use an ivar in a method that is being called from a block. Is it fine to call the ivar directly from it without causing a retain cycle?
I have seen other questions related to calling properties- saying that we 'can' use self. Just wanted to make sure about ivars, can we call ivar directly or do we need to use self->_myInstanceVariable explicitly?
__weak MyClassName *weakSelf = self;
[MyBlockCreator myBlock:^{
MyClassName *strongSelf = weakSelf;
[strongSelf doSomething];
}];
- (void) doSomething {
_myInstanceVariable = someObject
// is it fine to use the ivar directly above?
// or do we want use self explicitly?
// like self->_myInstanceVariable
}
In this case you don't need to make the reference weak/strong at all, the only situation in which you can cause a retain cycle is if self references a block and a strong version of self is captured within that block. Since self doesn't retain the block in question, there would be no retain cycle even using a strong reference.
[Foo doWithBlock:^{
bar.baz = #"Hello World"; // Totally fine without weak/strong since bar doesn't retain the block here.
}];
In situations where self holds a strong reference to a block and the block refers to self, you need to make the reference weak outside the block then make it strong again inside.
__weak id weakSelf = self;
[self doWithBlock:^{
id strongSelf = weakSelf;
strongSelf.baz = #"Ok";
}];

Objective-C Blocks: Is it ok to modify self in an external method if called from a weak pointer to self?

Can you modify self from an instance method called from a weak self pointer within a block?
-(void)someMethod:(AnotherClassName *)anObject {
__weak MyClassName *weakSelf = self;
[anObject requestSomethingWithCompletion:^{
[weakSelf updateSomething];
}];
}
-(void)updateSomething {
self.something = #"update"; // Will this cause a memory leak?
}
So basically I am calling an instance method from the same class I am in, but I am doing it from a weak pointer and then changing self.
According to Apple's Programming with Objective-C Guide this is how to call a method on self within a block but it isn't clear weather I can directly modify self in that method.
If you know the answer based on something you've read before please include the source.
Thanks!
You can modify properties and call methods. There will be no memory leaks.
But your block is not thread safe now. If requestSomethingWithCompletion will run block asynchronously your class (self) could be deallocated during block execution and weakSelf will become nil. This could cause problems (depends on what does your block do). Good practice to avoid this is to write it following way
-(void)someMethod:(AnotherClassName *)anObject {
__weak MyClassName *weakSelf = self;
[anObject requestSomethingWithCompletion:^{
MyClassName *strongSelf = weakSelf;
[strongSelf updateSomething];
}
}
-(void)updateSomething {
self.something = #"update"; // No leaks here!
}

memory/pointer behavior for self = [super init]

Forgiveness, please: I am a beginner. I was looking at another quesiton/answer and came across this code:
SpinningView *spinner = [[SpinningView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)]
// Now let's take a look at the implementation of SpinningView's -initWithFrame: method
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.backgroundColor = [UIColor clearColor];
}
return self;
}
I believe that, in the second section of code, self points to the instance to which the message was sent that resulted in "self" being encountered, i.e., the result of [SpinningView alloc]. (Or doesn't that produce an instance?)
So, when you call self = [super initWithFrame:frame] on the 4th line of code, are you not reassigning the pointer value associated with "spinner"? I.e, are you not abandoning the memory you allocated in the first line? Or does the compiler someone know just to copy memory values instead of changing the pointer value? Or... what??
Thanks!
This is the standard idiom for the -init method of obj-c objects. The idea being that, whatever was allocated from +alloc doesn't matter, only what was returned from -init matters. Now, -init will usually just use the already-allocated object that's in self. But it's not required to. It is free to deallocate that object and create a new one. The classic example is when you alloc/init an NSString* you don't actually get back an instance of NSString*, you get back a concrete subclass. This is because NSString* is a "class cluster". So when you call +alloc you get back an NSString*, but when you call -init it frees that object and reallocates an object of one of its subclasses, initializes that new object, and hands it back to you.
Another example would be if you had a class that tried to memoize itself. Lets say you have an immutable class that gets initialized with a number. You could change your -init to re-use existing instances of the class. Here's an example (note: not thread-safe):
static NSDictionary *numberCache;
#interface MyNumber : NSObject
#property (readonly) int number;
- (id)initWithInt:(int)i;
#end
#implementation MyNumber
+ (void)initialize {
if (self == [MyNumber class]) {
numberCache = [[NSDictionary alloc] init];
}
}
- (id)initWithInt:(int)i {
// find ourself in the numberCache
NSValue *val = [numberCache objectForKey:#(i)];
if (val) {
// yep, we exist. Release the just-allocated object
[self release];
// and retain the memoized object and stuff it back in self
self = [[val nonretainedObjectValue] retain];
} else if ((self = [super init])) {
// nope, doesn't exist yet. Initialize ourself
_number = i;
// and stuff us into the cache
val = [NSValue valueWithNonretainedObject:self];
[numberCache setObject:val forKey:#(i)];
}
return self;
}
- (void)dealloc {
// remove us from the cache
[numberCache removeObjectForKey:#(_number)];
[super dealloc];
}
#end
#KevinBallard covered most of the points. The reason we need the self = is because init is not guaranteed to return the same object it is called on (it could return a different object or nil). I will answer your questions and expand on the memory management aspects:
I believe that, in the second section of code, self points to the
instance to which the message was sent that resulted in "self" being
encountered, i.e., the result of [SpinningView alloc].
Yes
So, when you call self = [super initWithFrame:frame] on the 4th line
of code, are you not reassigning the pointer value associated with
"spinner"?
Yes. Not spinner (spinner doesn't exist at this point anyway). You are re-assigning the pointer variableself inside the method.
I.e, are you not abandoning the memory you allocated in the first
line? Or does the compiler someone know just to copy memory values
instead of changing the pointer value? Or... what??
Yes. Under MRC, you are just re-assigning the pointer, and the compiler does not do anything except change the pointer value. Under ARC, it's more complicated, but at the end of the day, the compiler just does the same as under MRC in this case, i.e. just re-assigns the pointer.
It's not really "abandoning" the memory if you think about it. You see, by convention, init methods take ownership of ("consume") an already-retained object that they're called on (usually the return result of a call to alloc), and they return a retained object. But these two don't have to be the same object. So when your init method is called, its self is already retained, and the init method owns it, but then it calls [super init...], which calls the superclass's init method on self, so that method now takes ownership of the self which your init had ownership to. And in return, that superclass's init returns back to you a retained instance, which you assign to self. You did not "abandon" self because you gave it to the superclass's init method, which in turn became responsible for memory managing it (including releasing it if it wants to return something else).

Objective-C proper use of blocks with ARC?

I know this question has been asked before, but non of the solutions solve my problem, so I'm asking this again. I am trying to call a method on self as the result of a callback through a block. I'm getting the following error:
Capturing 'self' strongly in this block is likely to lead a retain cycle
- (void)viewDidLoad {
[super viewDidLoad];
self.webClient.completionHandler = ^{
[self populateData];
};
}
I tried doing something like the code below, and I'm still getting the same warning.
What's the solution?
__weak id myself = self;
[myself populateData];
Your code should look like this:
- (void)viewDidLoad {
[super viewDidLoad];
__weak id weakSelf = self;
self.webClient.completionHandler = ^{
[weakSelf populateData];
};
}
UIAdam gave the correct answer, but it's worth understanding why it is correct.
First, why did you get the warning?
self has a strong reference to webClient. webClient has a strong reference to completionHandler. completionHandler has a strong reference to self. So if all other references in your program go away, there is still a strong reference to each item in this cycle, so they can never be deallocated.
The attempt of writing
__weak id myself = self;
[myself populateData];
doesn't work of course. The block still references self because it is assigning it to myself. So no difference here.
UIAdam's solution of writing
__weak id weakSelf = self;
self.webClient.completionHandler = ^{
[weakSelf populateData];
};
means that weakSelf is a weak reference, and the block only contains a weak reference to self. So if all other strong references to self is gone, there's only a weak reference left. A weak reference doesn't keep self alive, so self gets deallocated.
Now what if that happens, but something else had a strong reference to webClient and your block is called? weakSelf is a weak reference, and weak references are set to nil when the object is deallocated. So you have to be prepared that weakSelf is nil when your block gets called. It is actually better to write
id strongSelf = weakSelf;
[strongSelf populatedData];
inside the block: strongSelf might be set to nil, or it will be set to self. But since it is a strong reference, it will stay non-nil until the block has finished. If it was not nil to start with.

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...