So, I know that if you save a block inside of self, then access self inside of that block you need to create and use something like __weak id weakSelf = self;.
My question is, does this also extend to functions being called from that block? As in, would the following lead to a retain cycle:
self.block = ^{ [weakSelf myFunction]; }
- (void) myFunction { self.counter++; }
Thanks for your time!
This does not create a retain cycle, because the self in the method is actually a parameter passed by the Objective C runtime (using objc_msgSend and similar). So let's consider the two scenarios possible in your code example. weakSelf has been zeroed out due to release of the holding object - a message passed to nil is ignored. weakSelf is not zeroed, in which case, it is passed by the Objective C runtime to the message as its self parameter.
Related
I have a viewcontroller class and another class of NSObject. I call from the viewcontroller class with the following method the NSObject class.
SubmitContentViewController class
#implementation SubmitContentViewController
-(void)viewDidLoad{
[self callUploadQueueClass];
}
-(void)callUploadQueueClass{
UploadQueueClass *queue = [UploadQueueClass new];
[self generateIDforImage];
}
#end
UploadQueueClass
#implementation UploadQueueClass
-(void)generateIDforImage{
#weakify(self)
[[[ApiServicesProvider shared] userService] getCreatorsContentID:^(NSDictionary * _Nullable result, NSError * _Nullable error) {
#strongify(self)
if(nil==error){
NSString* ccID = result.creatorsContentId;
self.creatorsContentID = ccID;
NSLog(#"creatorsContentID %#",self.creatorsContentID);
[self getImageUploadURL:ccID withNumberOfAttempts:10];
}
else{
self.isUploading = NO;
}
}];
}
#end
at this line
NSLog(#"creatorsContentID %#",self.creatorsContentID);
creatorsContentID is null although at this line
self.creatorsContentID = ccID;
ccID is not null so self.creatorsContentID should not be null.
Moreover at this line
[self getImageUploadURL:ccID withNumberOfAttempts:10];
is never get called.
What am i missing?
You are creating your UploadQueueClass instance as a local variable *queue in callUploadQueueClass.
This local variable holds a strong reference to the UploadQueueClass instance.
As soon as the function returns, that local variable is released and it no longer holds the strong reference.
This happens before getCreatorsContentID has completed its work. Before the completion handler block is called.
You have used #weakify so that the self captured by the block does not hold a strong reference to the UploadQueueClass instance. The local variable has been released and the block self doesn't hold a strong reference to the instance. Nothing does, so it is released.
The self in the block is now nil. Using #Strongify won't help you here; the object has already gone away;
In this case you don't need to use #weakify; There is no danger of a circular reference causing a memory leak; The blocks capture of self only lasts until the completion handler has done its work.
However, removing #weakify doesn't seem like it would really help since there doesn't seem to be any way for the UploadQueueClass instance to communicate its results back to the calling view controller.
It would be more typical for the view controller to provide the completion handler block to the function it is calling, or at least provide some block to be executed. This is where you could use #weakify since the view controller instance would be self, but the block doesn't need to hold a strong reference to it to keep it around; The view controller hierarchy is doing that.
Since you don't want this object to report back to the view controller, simply remove the #weakify/#strongify. Then the block itself will hold a strong reference to the UploadQueueClass instance until it returns and then the object will be released by ARC.
Let say :-
I have a ViewController created in objeticve - c (Number.m).
I have a TableViewCell created in swift which contains button (CalculateSum.swift)
Now i need to tell VC that button has been tapped and send tag of the button. For this i use closure.
Swift :-
var calculateSumBtnTapped: ((UITableViewCell) -> Void)?
#IBAction func calculateSumBtnDidTapped(_ sender: Any) {
self.calculateSumBtnTapped?(self)
}
Now as we see CalculateSum.swift holds strong reference to calculateSumBtnTapped property.
Now i call this closure as block in Number.m
CalculateSum * calculateSum = [tableView dequeueReusableCellWithIdentifier:#"sum" forIndexPath:indexPath];
__block typeof(self) weakSelf = self;
calculateSum.calculateSumBtnTapped = ^(UITableViewCell * _Nonnull calculateSumCell) {
// calculating sum by tag
weakSelf.sum = weakSelf.sum + calculateSumCell.tag
};
Is it necessary to use self as weakself ? or I can use self as it is ?
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.
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.
When an object A reference another object B strongly and object B references object A strongly, ARC cant dealloc there two objects thus creating retain cycle which may increase the memory footprint of your app and may cause app to crash. To avoid retain cycle one of the reference should be weak. Thats why you need to use weakSelf inside the block.
I have been always getting warning when trying to use "self" in blocks until this:
__weak typeof(self) weakself = self;
[self.segmControl setSegmPosition:^(int position) {
[weakself.scrollView scrollRectToVisible:CGRectMake(self.view.size.width*position, 0, weakself.view.size.width, weakself.view.size.height-10) animated:YES];
[weakself.segmControl setScrlView:position];
}];
[self.view addSubview:self.segmControl];
It's not always a problem to use self in a block; the warning is issued if the compiler thinks that doing so will lead to a circular reference. That is, using self in a block causes the block to hold on to the object referenced by self; that's no big deal unless the self object also holds a strong reference to the block.
The code you posted is of the form:
[self.foo method:^{ [self bar]; }]
That's not obviously a problem. The block is going to capture self, but then you are passing it to the method on an object that self is only holding a reference to. It might create a circular reference, but it might not. We'd have to know what happens inside the method, which is difficult for the compiler to know for certain; even if you have the source code to method method: the compiler can't be certain you're calling that implementation until runtime.
Contrast that with:
self.foo = ^{ [self bar]; }
In that case, the block is capturing self and is holding on to a strong reference to the block (assuming foo is defined as #property (strong)). In this case the compiler can be more-or-less certain that you are creating a circular reference here, and so it will warn you.
I'm trying to get variables and properties in self in a block for actions to complete, but, if I reference self or a global variable in self when self is the object running the block, it warns me of a retain loop. Here's what I'm doing:
I'm adding actions to an NSMutableArray that are of type (void(^)() (in other words, a block returning void with no parameters).
I call it using this syntax later on, where i is an int determined by code (that is in the bounds of the array:
void (^someBlock)() = arrayOfActions[i];
someBlock();
The code works and runs fine, but, because I use properties of self within the block, Xcode warns me of a retain loop. Should I ignore it because it's simply a warning and everything works fine in code (it only executes the block once), or should I do something different?
You should definitely not ignore the warning, but use __weak instead to define a weak reference and eliminate retain cycles as described in the documentation:
__weak SelfType *weakSelf = self;
void (^aBlock)() = ^(){
SelfType *strongSelf = weakSelf;
//User strongSelf
};
Alternatively you can use libextobjc (https://github.com/jspahrsummers/libextobjc) with its convenient #strongify and #weakify annotations.
Mike Ash has written this introduction to ARC where he introduces something like:
__weak Foo *_weakFoo = [object foo];
Why would I want to do that for a local, temporary variable? __weak is a zeroing reference which will set the _weakFoo pointer automatically to nil as soon as the referenced object gets deallocated. Also, __weak is only available in iOS >= 5.
When would I run into trouble when I simply do this?:
Foo *_weakFoo = [object foo];
This is always expected to return an object or nil. My guess is this:
Foo *_weakFoo = [object foo];
[self doSomethingStupid]; // does something bad so foo gets deallocated
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456
One thing that still bugs me with ARC is: When does it know that I don't need an object anymore? I'd argue that when I set a pointer to nil or to something else it figures out that the previously referenced object isn't needed by this owner anymore and therefore maybe can go away. But the point is: I set it to nil. So it's nil anyways!
So when would __weak for a local variable make sense, and what kind of crazy thing must I do somewhere else so that I really need that?
I use __weak local variables if I have to manipulate self inside of a block to avoid a retain cycle. Consider this example where I'm using GCD and blocks to perform a network request for a string, and then setting it on a label declared by the class, in this case, TurtlesViewController.
__weak TurtlesViewController *weakSelf = self;
dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(networkQueue, ^{
// Kick off a network task for some data that is going to populate a label declared on our class
NSString *returnString = [networkDataSource retrieveTurtleTime];
// Dispatch back to the main thread to populate the UILabel
dispatch_async(dispatch_get_main_queue(), ^{
// Using self.label here creates a retain cycle. Self owns the block and the block has captured self
self.label.text = returnString;
// Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop.
weakSelf.label.text = returnString;
});
});