The custom transition API is not that well documented and required a lot of trial and error for me to get everything right.
\n\nLet me walk you through how I was able to make it work nicely without any memory issues:
\n\nVCA = The view controller that wants to present VCB modally
\nVCB = The modally presented view controller (presented by VCA)
TC = The custom transition controller object that performs the custom animation.
\nNSObject subclass that conforms to \"UIViewControllerAnimatedTransitioning\".
\nWill be instantiated within TD.
TD = The custom transition delegate object that provides the transition controller to the system.\nNSObject subclass that conforms to \"UIViewControllerTransitioningDelegate\"
\n\nself = an instance of VCA
\nmyModalViewController = is a strong property of self
self.myModalViewController = [[VCB alloc] init];\n\n[self.myModalViewController setModalPresentationStyle: UIModalPresentationCustom];\n[self.myModalViewController setTransitioningDelegate: [[TD alloc] init]];\n[self presentViewController: self.myModalViewController\n animated:YES \n completion:NULL];\n
\n\nself = an instance of VCA
\nmyModalViewController = the modally presented instance of VCB presented earlier
[self dismissViewControllerAnimated:YES \n completion:^{\n [self.myModalViewController setTransitioningDelegate: nil]; // DO THIS!!!! \n self.myModalViewController = nil;\n }];\n
\n\nI hope this helps. It certainly did for me.
\n","author":{"@type":"Person","name":"tiescher"},"upvoteCount":6}}}Reputation: 233
I'm creating custom transitions in my app and running into two problems. If I set the view controller to handle both UIViewControllerAnimatedTransitioning
and UIViewControllerTransitioningDelegate
I run into the problem of my view controller never being deallocated. Specifically, this creates the retain:
self.transitioningDelegate = self;
If I don't do that, and put UIViewControllerAnimatedTransitioning
and UIViewControllerTransitioningDelegate
in a separate NSObject
called TransitionController and set it like this:
self.transitioningDelegate = [[TransitionController alloc] init];
the UIViewController
is deallocated, but I get memory leaks on the TransitionController object. Does anyone now what I'm doing wrong?
Upvotes: 8
Views: 4690
Reputation: 13511
In my case, what was causing the retention of my presented view controller was that I was passing the wrong boolean to the completion block of my animation.
[transitionContext completeTransition:transitionContext.transitionWasCancelled];
It should have been this:
BOOL successful = transitionContext.transitionWasCancelled == NO;
[transitionContext completeTransition:successful];
Splitting the code into two lines helps readability.
Upvotes: 0
Reputation: 40661
The UIViewControllerAnimatedTransitioning
object is retained by the 'from' VC after the transition finishes in iOS7 (this doesn't happen in iOS8) which can cause memory leaks if your transition object stores anything in properties. This bit me in the past, something to be careful of.
Upvotes: 0
Reputation: 9975
In my case I had self (UIViewController
) holding an instance of a custom UIViewController
(lets call it mViewController
), and self
is the transitioningDelegate
of showing/dismissing mViewConroller
. My solution to avoid retain-cycle was to call this inside the .m
of mViewController
:
-(void)viewDidDisappear:(BOOL)animated {
self.transitioningDelegate = nil;
[super viewDidDisappear:animated];
}
Worked like a charm (:
Upvotes: 2
Reputation: 271
I ran into the same issue and was able to solve it.
The custom transition API is not that well documented and required a lot of trial and error for me to get everything right.
Let me walk you through how I was able to make it work nicely without any memory issues:
VCA = The view controller that wants to present VCB modally
VCB = The modally presented view controller (presented by VCA)
TC = The custom transition controller object that performs the custom animation.
NSObject subclass that conforms to "UIViewControllerAnimatedTransitioning".
Will be instantiated within TD.
TD = The custom transition delegate object that provides the transition controller to the system. NSObject subclass that conforms to "UIViewControllerTransitioningDelegate"
self = an instance of VCA
myModalViewController = is a strong property of self
self.myModalViewController = [[VCB alloc] init];
[self.myModalViewController setModalPresentationStyle: UIModalPresentationCustom];
[self.myModalViewController setTransitioningDelegate: [[TD alloc] init]];
[self presentViewController: self.myModalViewController
animated:YES
completion:NULL];
self = an instance of VCA
myModalViewController = the modally presented instance of VCB presented earlier
[self dismissViewControllerAnimated:YES
completion:^{
[self.myModalViewController setTransitioningDelegate: nil]; // DO THIS!!!!
self.myModalViewController = nil;
}];
I hope this helps. It certainly did for me.
Upvotes: 6
Reputation: 1181
In the second try, you are allocating a TransitionController
instance and it will be never released (as nobody has a reference to it).
The objects should never retain it's delegates in Objective-C, so you need to have reference to your ViewController
and to it's delegate
from an other point of your code.
Upvotes: 0