سؤال

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?

هل كانت مفيدة؟

المحلول

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top