Situation: there is UINavigationController with pushed UIViewController.
1.UIViewController has strong reference to UINavigationController
@property(nonatomic,readonly,retain) UINavigationController *navigationController
2.UINavigationController stores view controllers in NSArray
@property(nonatomic,copy) NSArray *viewControllers;
UINavigationController should have strong reference to this NSArray (or it will be deallocated).
3.NSArray has strong references to contained view controllers.
UPDATE: Lets imagine somewhere in code we have following:
UIViewController *A = [ [UIViewController alloc] init ];
UINavigationController *B = [ [ UINavigationController alloc ] initWithRootViewController:A ];
// Here we have strong reference in A to B, in B to B.viewControllers (count == 1) and in B.viewControllers to A.
// Local variable's strong references to A and B
A = nil; B = nil;
// Local variable's strong references has gone
// But we should still have retain loop here
// Magic !?? :)
My question is why we do not have retain loop here?
@MainActor class UINavigationController : UIViewController A navigation controller is a container view controller that manages one or more child view controllers in a navigation interface. In this type of interface, only one child view controller is visible at a time.
When the active view controller changes, the navigation controller updates the toolbar items to match the new view controller, animating the new items into position when appropriate.
A navigation controller object manages an optional toolbar in its view hierarchy. When displayed, this toolbar obtains its current set of items from the toolbarItems property of the active view controller.
To hide or show the navigation bar, use the is Navigation Bar Hidden property or set Navigation Bar Hidden(_: animated:) method. A navigation controller builds the contents of the navigation bar dynamically using the navigation item objects (instances of the UINavigation Item class) associated with the view controllers on the navigation stack.
2.UINavigationController stores view controllers in
NSArray
That is not a given.
@property(nonatomic,copy) NSArray *viewControllers;
That in no way indicates that there is an ivar called _viewControllers
or anything like it. It just tells us that there is some method -viewControllers
that will return us an NSArray
, and that there is some method setViewControllers:
that will accept one, and hints that it will make a copy of it (or at least behave like it made a copy of it). That is all it tells us. If you expand an NSNavigationController
in the debugger, you'll notice that there is no _viewControllers
ivar listed there.
If you poke around a little, you'll find that -viewControllers
is not implemented as a synthesized property. It just forwards onto -childViewControllers
(which is a UIViewController
property). OK, so doesn't that just move the problem? I mean -childViewControllers
is implemented as [NSArray arrayWithArray:_childViewControllers]
. Fair enough. You caught me.
But the same logic applies to [UIViewController navigationController]
. This declaration:
@property(nonatomic,readonly,retain) UINavigationController *navigationController
does not mean that it actually has a strong link. It just means that if you called setNavigationController:
, you would expect it to retain it. But you can't call setNavigationController:
. There is no such method (not even a private one). So all this is really promising is that there is a method called -navigationController
. And it's implemented as a call to +[UINavigationController _ancestorViewControllerOfClass:allowModalParent:]
. That just passes on to the UIViewController
implementation, which walks up the parentViewController
chain looking for a UINavigationController
. So there's no retain loop; it's dynamically determined.
But your question is still a good one. The header file here is confusing IMO, and I would open a radar against it. navigationController
should be listed as assign
or it should say nothing (even if that defaulted to strong
it would at least not be misleading).
BTW, if this stuff interests you, you really should drop $90 for Hopper. It's very good at this kind of exploration.
The viewControllers
property of UINavigationController
is defined as
@property(nonatomic, copy) NSArray *viewControllers
The view controllers currently on the navigation stack.
Then there is no problematic retain loop since the navigation controller removes any UIViewController
from that array when the view controller is dismissed.
A retain loop is an issue when you do not have any mechanism to open the loop by releasing the retained object at some point (using release
if non-ARC, or setting a strong property to nil
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With