I want to get arraycount inside handler.and then call webservice according to Count,.But array count give me array.
__weak NewsViewController *self_ = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%lu",(unsigned long)[tableDataArray count]); // This Line give error Capturing self strongly in this block lead to retain cycle;
[self_ callWebService];
}];
Try create a weak pointer to tableDataArray also (like self)
__weak typeof(NSMutableArray*) _w_tableDataArray = tableDataArray;
__weak NewsViewController *self_ = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%lu",(unsigned long)[_w_tableDataArray count]); // This Line give error Capturing self strongly in this block lead to retain cycle;
[self_ callWebService];
}];
Although you're creating a weak self you're not actually referencing it in the block. When you call [tableDataArray count]; It's the equivalent of calling self.tableDataArray in your case you should be calling self_.tableDataArray;.
For clarity an exemplary use of this is as follows:
...
#property (nonatomic, strong) NSMutableArray *tableDataArray;
...
...
__block __weak NewsViewController *welf = self;
[table addInfiniteScrollingWithActionHandler:^{
NSLog(#"%li", welf.tableDataArray.count);
[welf callWebService];
}];
Yes welf stands for weak self.
Related
Recently after following Apple documentation
I used the following conventions to avoid retain cycle issues.
__weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){
__typeof(self) strong_self = weak_self;
if (strong_self) {
if (strong_self->_completion != NULL) {
strong_self->_completion();
}
}
};
But this code is found to be crashing because self is getting deallocated before invoking the block.
When I used the following it is found to be working.
__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){
if (block_self->_completion != NULL) {
block_self->_completion();
}
};
Now I am confused when we should use __weak reference. Only in the following case of "self.completionBlock"
__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
if (weak_self->_completion != NULL) {
weak_self->_completion();
}
};
Any light on this conditions will be very useful to me.
My implementation code is given below.
=================================================
File MyViewController
#implementation MyViewController
//starting point
- (void)myPushMethod {
__weak __typeof(self) weak_self = self;
MyViewControllerTransitioning *delegateObj = [[MyViewControllerTransitioning alloc] initWithCompletion:^{
//resetting the delegate
__typeof(self) strong_self = weak_self;
if (strong_self) {
strong_self.navigationController.delegate = nil;
}
}];
self.navigationController.delegate = delegateObj;
[self.navigationController pushViewController:someViewController animated:_animated];
//it is found that delegateObj is getting deallocated while reaches this point
}
#end
=================================================
File MyViewControllerTransitioning
#implementation MyViewControllerTransitioning
- (instancetype)initWithCompletion:(completionHandler)completionHandler
{
if(self = [super init])
{
if (completionHandler != NULL) {
_completion = completionHandler;
}
}
return self;
}
- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
id<UIViewControllerAnimatedTransitioning> animationTransitioning = nil;
//crashes here
__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){
if (block_self->_completion != NULL) {
block_self->_completion();
}
};
//showing presentation-up animation if Push
if (operation == UINavigationControllerOperationPush) {
animationTransitioning = [[MyAnimator alloc] initWithAnimationCompletion:completionBlock];
}
return animationTransitioning;
}
- (void)dealloc{
//dealloc is called before invoking completionBlock
}
#end
=================================================
File MyAnimator
#implementation MyAnimator
- (instancetype)initWithAnimationCompletion:(presentationUpCompletion)completionHandler
{
if(self = [super init])
{
if (completionHandler != NULL) {
_completion = completionHandler;
}
}
return self;
}
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return my_duration;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//animation logic
[UIView animateWithDuration:duration animations: ^{
//animation logic
} completion: ^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
- (void)animationEnded:(BOOL) transitionCompleted {
if (transitionCompleted && _completion != NULL) {
_completion();
}
}
#end
In my original answer, below, I walk through the standard weakSelf pattern (and the weakSelf-strongSelf "dance"). My conclusion was that presentation slide you reference is absolutely correct regarding the weakSelf pattern (though that presentation is stylistically dated).
You subsequently provided a more complete code sample, and it turns out that it suffers from a different, unrelated problem. (Worse, it was a problem that only manifests itself when the strong reference cycles are resolved. lol.) Bottom line, the code sets the delegate of the navigation controller to a local object which falls out of scope. Because the navigation controller doesn't retain its delegate, you were ending up with a dangling pointer to this deallocated object.
If you keep your own strong reference to this delegate object (keeping it from being deallocated), the problem goes away.
My original answer is below.
You said:
used the following conventions to avoid retain cycle issues.
__weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){
__typeof(self) strong_self = weak_self;
if (strong_self) {
if (strong_self->_completion != NULL) {
strong_self->_completion();
}
}
};
But this code is found to be crashing because self is getting deallocated before invoking the block.
No, this is a very common pattern (often jokingly called the "weak self, strong self dance"). There is nothing wrong with this. If it's crashing, it's for other reasons.
Sure, I'd use modern naming conventions (weakSelf and strongSelf rather than weak_self and strong_self). And I'd remove the __ at the start of __typeof. And I wouldn't be inclined to dereference and ivar, but rather use a property. So, I might end up with something like:
__weak typeof(self) weakSelf = self;
void(^completionBlock)(void) = ^(){
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
if (strongSelf.completion != NULL) {
strongSelf.completion();
}
}
};
But, still, if that is crashing, you have some other problem. Frankly, you have a block calling a block so it's a little hard to guess where your problem rests, but the problem is not in the "weak self" pattern.
Later you go on to suggest using:
__block __typeof(self) block_self = self;
That does not do what you think it does. The goal of the "weak self" pattern is to break the strong reference cycle (formerly known as retain cycle), but in ARC, this __block reference does nothing to resolve that strong reference cycle. Note, in non-ARC code, this block_self pattern was used to break retain cycles, but it will not do the job in ARC.
Finally, you go on to suggest:
__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
if (weak_self->_completion != NULL) {
weak_self->_completion();
}
};
This has two serious problems. First, you are dereferencing a weak variable. If weak_self was nil, it would crash. Second, even if you fixed that by using property accessor methods rather than dereferencing ivars, you have another problem here, namely a race condition.
Bottom line, the "weak self" pattern from that presentation is correct. Likewise, the "weak self, strong self dance" from your first example is also correct. If it's crashing for you, you have to provide us a MCVE which reproduces the problem. But in ARC code, this is a perfectly valid pattern.
self.completionBlock
self has a strong reference to completionBlock (it's a property variable), then u need to weak reference to self to avoid the cycle.
(void)(^completionBlock)(void) = ^{}
self has NO strong reference to completionBlock (it's a local variable), no need to create a weak reference to self.
And the reason for the one you added __block works is that "__block causes the variable to be strongly referenced".
I am looking for retain cycles in my block in my code. I have the following code in my UITableViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//[...] Not important code.
__weak ELParkingLocationTVC *weakself = self; // Required? (1)
cell.completionBlock = ^ {
__strong ELParkingLocationTVC *strongSelf = weakself; // Required? (2)
__weak ELParkingLocationTVC *weak2self = weakself; // Required? (3)
[strongSelf dismissViewControllerAnimated:YES completion:^{
__strong ELParkingLocationTVC *strong2self = weak2self; //Required? (4)
ELMenuHistoryTVC *menuTVC = [strong2self.navigationController.viewControllers firstObject];
[menuTVC.parentTabBarController moveToTab:ELMapViewControllerIndex completion:^(BOOL finished) {
ElMainMapViewController *mainMapViewController = menuTVC.parentTabBarController.viewControllers[ELMapViewControllerIndex];
//ELCustomParkplace *customParkplace = [strong2self parkplaceAtIndex:indexPath.row]; //(5)
[mainMapViewController moveToCoordinate:customParkplace.coordinate];
}];
}];
};
}
And have the following questions:
Which __weak and which __strong reference do I need? I am sure that 1st and 2nd I have to use, but I am really not sure about 3rd and 4th.
Can I use #strongify and #weakify here?
I think I don't need line (5), but I am not sure.
Any suggestion, link or nice comment will be appreciated!
You do need a weak reference for the cell completion handler, because you have a reference cycle: self > UITableView > UITableViewCell > self.
You do not need to use the __strong qualifier. Variables are strong references by default.
You do not need a weak reference for the animation and transition completion handlers, as those blocks are released as soon as the transition completes, but in this case they can't use self because they're nested inside of a block that can't capture self.
So keep weakSelf and strongSelf, and use the same strongSelf variable inside all of the nested blocks.
Is the following declaration and call a strong or weak reference? I know that a strong reference inside an NSNotificationCenter block can lead to a retain cycle, so I'm trying to avoid that.
Declaration:
#interface MPOCertifiedAccountsViewController : MPORootViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *certifiedTableView;
}
Call:
- (id)init
{
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserverForName:MPOFriendManagerManagerDidFinishRefreshingLocal
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
[certifiedTableView reloadData];
}];
}
return self;
}
All instance variables are by default strong. However, that is not relevant here because
[certifiedTableView reloadData];
is in fact
[self->certifiedTableView reloadData];
and that retains self, not the instance variable. So you have a retain cycle here,
independent of whether certifiedTableView is a strong or weak instance variable.
You can solve that with the well-known technique of creating a weak reference to self:
__weak typeof(self) weakSelf = self;
which is used in the block:
typeof(self) strongSelf = weakSelf;
if (strongSelf != nil) {
[strongSelf->certifiedTableView reloadData];
}
You should also consider to use a property instead of an instance variable.
With self.certifiedTableView you see immediately that self is retained.
I have a project I am working on, to learn some more about JSON and restkit. It all is working great, however I am having trouble with an array losing it's values.
This is the last method that is executed in my network request.
SHRetrieveStoresWS.m
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
self.stores = [[NSArray alloc] initWithArray:objects];
StoresViewController *viewController = [[StoresViewController alloc] init];
[viewController didLoadObjects:objects];
for (Store *aStore in stores) {
NSLog(#"%#", [aStore longName]);
}
}
Which calls this method in my view controller.
StoresViewController.m
#property (strong, nonatomic) NSArray *data;
- (void)didLoadObjects:(NSArray *)aArray
{
NSLog(#"%d", aArray.count);
self.data = [[NSArray alloc] initWithArray:aArray];
NSLog(#"%d", data.count);
[self.tableView reloadData];
}
The values are correct when I ask for the values within this method, but the array shows 0 objects immediately afterwards. Am I missing something here?
I am later checking the value with this method.
- (IBAction)pushMe:(id)sender
{
NSLog(#"Data: %d", self.data.count);
}
You should pass the data in the segue...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString: #"MY_IDENTIFIER"]){
StoresViewController *viewController = segue.destinationViewController;
[viewController didLoadObjects: objects];
}
}
That should work for you! Just change MY_IDENTIFIER to whatever the identifier of your segue is.
StoresViewController is initialised as a local variable which is only accessible in the method that it was declared (aka objectLoader). After objectLoader has completed, the local variable is no longer valid.
The problem is most likely that you're creating multiple instances of StoresViewController instead of giving your network controller a reference to the original instance.
You can demonstrate it to yourself by printing out self in -viewDidLoad and again in didLoadObjects:. You'll see that the pointer addresses are different.
This line is the culprit:
StoresViewController *viewController = [[StoresViewController alloc] init];
Instead of instantiating StoresViewController again, add a property to your SHRetrieveStoresWS class and use it to hold a reference to your view controller.
#property (strong) StoresViewController *viewController;
You'll need to set that property before -didLoadObjects: is invoked.
I usually get a warning when I call anything on self in a block retained by self:
[self.someView doSomething:^{
self.aVar = #"Hello!";
}];
I have to do:
__weak SomeObject *weakSelf = self;
[self.someView doSomething:^{
weakSelf.aVar = #"Hello!";
}];
But if I call a method on weakSelf, and that method uses self, will that lead to a retain cycle even though I don't get a warning? I am talking about this:
__weak SomeObject *weakSelf = self;
[self.someView doSomething:^{
weakSelf.aVar = #"Hello!";
[weakSelf aMethod];
}];
and aMethod uses self
As long as your weakSelf is declared outside your block, there is no retain cycle.
Use of objects inside the block implicitly increments the retain count. But you'd be calling aMethod on weakSelf rather than self, so the retain count is not affected.
You should declare the __weak to self outside of your block:
__weak SomeObject *weakSelf = self;
[self.someView doSomething:^{
weakSelf.aVar = #"Hello!";
[weakSelf aMethod];
}];
Else the compiler would have already retained self since it is used with the block.
Beter even is using the __block directive, because __weak is iOS 5 and higher only.
__block SomeObject *weakSelf = self;
[self.someView doSomething:^{
weakSelf.aVar = #"Hello!";
[weakSelf aMethod];
}];
About an other method calling self and causing retain, I've never seen this behavior. I always use the __block directive which might catch that one as well.