On Nov 19, 2008, at 7:00 AM, Brian Stern wrote:
There are competing issues. Following this best practice forces me to add public properties for all my outlets that my code never uses. This violates encapsulation and seems wasteful and error-prone.


No, it's not.  The nib-loading mechanism uses these methods.
It is precisely by using these methods that you avoid violation of encapsulation (notably on the desktop, where otherwise the instance variables may be set directly). Further, as others noted, if you want to avoid declaring the properties publicly as read/write, you can declare then as read-only then re-declare them as read/write in a private extension. Moreover it precisely avoids errors by providing a consistent pattern that will work across all platforms and that you can use without having to think about it. As we seem to agree, having to think about how to declare/use outlets per se is a waste of mental effort.


That's the reason I didn't do this earlier. The one little paragraph in the documentation that addresses this says I 'should' do it this way but doesn't explain why.

Because it should be obvious from a memory management perspective why this is the case. And the documentation typically tries to avoid repeating the basic rules of memory management.


I'll point out that the paragraph that explains memory management of outlets on Mac OS X on that page is half the length of the iPhone paragraph, and I'd maintain that the iPhone paragraph isn't long enough.

I don't see what's missing from the iPhone discussion. You're told that although the nib-loading mechanism doesn't retain the outlets directly, it uses KVC to set the outlets and what the ramifications are of that...


However, UIViewController has the ability to unload its view outlet in response to a memory warning. Any subclass should also release its outlets in response to the memory warning, if the base class releases its view, but not otherwise. So now there are three places to manage the memory of these outlets. The problem is that the base class doesn't always release its view in response to a memory warning and as far as I can tell the subclass has no clean way of telling if the view will be released or has been released. That's the problem.

You're shifting the goalposts; this is not the problem you originally described.

It's not me who has shifted the goalposts. The whole playing field was moved out from under me when it was decided to retain outlets by default, which is different from how this all works on Mac OS X.

No, it's not. Again as the documentation points out, exactly what happens on Mac OS X depends on the context. Most outlets are indeed not retained, but top-level objects *are* retained (so you do need to release them). What "The Nib Object Life Cycle" doesn't mention -- but probably should -- is that this is further complicated by what is the superclass of File's Owner -- if it's NSDocument, NSWindowController, or NSViewController, then you don't have to release top-level objects.

As I wrote originally, this is a mess, and requiring developers to think about this every time they make connections is unproductive. Which is why having a simple, consistent, approach that can be applied pervasively is beneficial. As ever, you are free to deviate from that if you want to expend additional mental effort...


You can add to your list of problems 'insufficient documentation and education of memory management of outlets.'

It remains unclear in what respect the document is insufficient.

There are several issues:
The template clearly indicates what should be done:
Obviously the client code can't touch _view or self.view in didReceiveMemoryWarning. That's why I said upthread that there's no clean way for the client code to tell if the view will be unloaded or has been unloaded.

Yes, there is...


In theory, you should simply check whether the view has a superview:
but since _view is declared as @package, you can't do that.
You could invoke 'view':
but this has the disadvantages that (a) in some situations it will cause the view to be loaded before it is subsequently unloaded, and (b) it isn't future proof.
self.view will always be non-nil.

[self.view superview] may, however, be nil, and this is what's important. If you use this test, then you might temporarily load some unwanted objects which in the context of a memory warning is counter-productive but in most cases the overhead -- if any -- should be minor compared with the data you're expunging. Nevertheless this is ultimately unsatisfactory.


This is why I 'shifted the goalposts.' There are many issues related to memory management of outlets on iPhone. Suggesting that everyone just follow your best practice described at the top obviously isn't sufficient.

On the contrary, following the best practice is sufficient, as it pertains to managing references to outlets.
There may be additional considerations on any platform, though.

The worst that will happen if, on iPhone, you simply use:

@property (nonatomic, retain) IBOutlet Class *outletName;
and follow standard memory management rules by releasing in dealloc
and do nothing else

is that your didReceiveMemoryWarning method will be less efective than would otherwise be the case. You'll be maintaining views that could have been disposed of. Hence:

This leaves us for now with two solutions:
(a) Greg's (override setView:) which is more future-proof but is in many respects academically unsatisfying. (b) For non-top-level-object, specify an assign attribute for the property -- and risk dangling pointers.


This, though, is again not wholly satisfactory, and there should be architectural support to avoid this...



And just to be clear, to step back for a moment, best practice does not *introduce* a problem with view controllers in this situation.

First, the situation is largely orthogonal to the use of properties/ following best practice. You have to ensure you dispose of resources when you receive a memory warning. How you do that is up to you. It was, though, in part by following best practice that this issue came to light...


To elaborate:
Because the nib-loading mechanism uses KVC --  in theoryyou have to:
(a) Remember to release outlets in dealloc;
(b) Remember to release outlets when you receive a memory warning.

If you haven't specified properties, it may be less clear that (b) is something to consider. If you haven't specified properties/accessor methods and forget about (b), then you will actually leak objects if you get a memory warning and you subsequently re-load your nib.


Following best practice means that:
You don't have to think about (a) -- it's a natural consequence of retaining properties. If you forget about (b), you don't actually ever leak objects -- you just don't expunge as many as you might be able to.


And one might hope that in the fullness of time there would be some other feature that would guide you properly in the direction of fulfilling (b) without having to think hard about it.


mmalc


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to