Interface Builder & Wiring Objects

  • Good afternoon!

    I am trying to learn Cocoa and am having difficulty remembering which
    direction to CTRL-drag controls to wire up the controls in Interface
    Builder.  For example, dragging from my button to my App Controller
    (NSObject) or vice versa.  Does anyone have a way to explain this that
    might make it stick?

    It seems to me that a button should make a call to my App Controller
    when the click event is fired; therefore I should CTRL-drag FROM the
    button TO the NSObject. This would allow me to select the appropriate
    Received Action (ie, "doSomething", etc.").  However, if I need to do
    something with a text box (read from it) and a table view (insert an
    item), I should go the other way... since I'm going to fetch from the
    text field and then insert into the NSArray that is feeding the text
    view.

    Sorry for such a noob question.  Thank you, in advance, for your
    patience and assistance.

    -- Greg
  • With new versions of IB, it's not even necessary to remember. Simply
    right-click on an object and it will bring up a HUD with the list of
    outlets or sent messages or whatever you need. Alternatively, you can
    view this list in the outlets tab of the inspector window.

    Even if the outlet you need is in a different object than the one
    you've selected, you can just drag from the "new referencing outlet"
    option to the object with that outlet. Using this right-click
    technique, selection is possible in either direction.

    Luke

    On Nov 17, 2008, at 10:09 AM, Greg Deward wrote:

    > Good afternoon!
    >
    > I am trying to learn Cocoa and am having difficulty remembering
    > which direction to CTRL-drag controls to wire up the controls in
    > Interface Builder.  For example, dragging from my button to my App
    > Controller (NSObject) or vice versa.  Does anyone have a way to
    > explain this that might make it stick?
    >
    > It seems to me that a button should make a call to my App Controller
    > when the click event is fired; therefore I should CTRL-drag FROM the
    > button TO the NSObject. This would allow me to select the
    > appropriate Received Action (ie, "doSomething", etc.").  However, if
    > I need to do something with a text box (read from it) and a table
    > view (insert an item), I should go the other way... since I'm going
    > to fetch from the text field and then insert into the NSArray that
    > is feeding the text view.
    >
    > Sorry for such a noob question.  Thank you, in advance, for your
    > patience and assistance.
    >
    > -- Greg
  • On Nov 17, 2008, at 11:09 AM, Greg Deward wrote:

    > Good afternoon!
    >
    > I am trying to learn Cocoa and am having difficulty remembering
    > which direction to CTRL-drag controls to wire up the controls in
    > Interface Builder.  For example, dragging from my button to my App
    > Controller (NSObject) or vice versa.  Does anyone have a way to
    > explain this that might make it stick?

    Aaron Hillegass, in his "Cocoa Programming for Mac OS X" book explains
    it this way:

    "Now you are going to introduce some objects to each other....To
    introduce one object to another, you will control-drag from the object
    that needs to know to the object it needs to know about."

    So, for instance, a class needs to know about its NSButton outlet, so
    you control-drag from the class to the NSButton in the window (to set
    the IBOutlet).  The NSButton needs to know what method to call when it
    is pressed, so you control-drag from the button to the class (to set
    the IBAction).

    Or do what Luke said in his response... :)

    > It seems to me that a button should make a call to my App Controller
    > when the click event is fired; therefore I should CTRL-drag FROM the
    > button TO the NSObject. This would allow me to select the
    > appropriate Received Action (ie, "doSomething", etc.").

    Yep, sounds like you have the basic gist of it...

    > However, if I need to do something with a text box (read from it)
    > and a table view (insert an item), I should go the other way...
    > since I'm going to fetch from the text field and then insert into
    > the NSArray that is feeding the text view.

    But, what triggers the action of reading from the text field and
    inserting that into the array that feeds the table (you said text, but
    I assume that's a typo) view?  A button gets pressed? The user presses
    Enter?  You set the action of the object that does that action just as
    you would otherwise.
  • As you pointed out, you have two kinds of relationship in IB: outlets and actions.
    > From a single object, you designate either an outlet object or a target object.
    For the target case, you have to specify the associated action selector.
    Usually though, you don't draw both kinds of connection from the same kind of objects.
    Controls send actions to target objects such as the First Responder.
    Controllers use outlets to reference other UI objects in source code.
    So you always CTRL-drag connections from your source object.

    With the introduction of Cocoa Bindings, you now have a third kind of relationship in IB: bindings.
    You don't have to CTRL-drag anything when using bindings since the connections are based on key path.
    However, you can mix both use of connections, such as connecting the File Owner of your nib to the content object outlet of an ObjectController instance.

    EG

    -----Original Message-----

    I am trying to learn Cocoa and am having difficulty remembering which
    direction to CTRL-drag controls to wire up the controls in Interface
    Builder.  For example, dragging from my button to my App Controller
    (NSObject) or vice versa.  Does anyone have a way to explain this that
    might make it stick?

    It seems to me that a button should make a call to my App Controller
    when the click event is fired; therefore I should CTRL-drag FROM the
    button TO the NSObject. This would allow me to select the appropriate
    Received Action (ie, "doSomething", etc.").  However, if I need to do
    something with a text box (read from it) and a table view (insert an
    item), I should go the other way... since I'm going to fetch from the
    text field and then insert into the NSArray that is feeding the text
    view.

    Sorry for such a noob question.  Thank you, in advance, for your
    patience and assistance.

    -- Greg
    ------------------------------------------------------------
    This message and any attachments (the "message") are confidential and intended solely for the addressee(s). Any unauthorised use or dissemination is prohibited. E-mails are susceptible to alteration. Neither DxO Labs nor any of its subsidiaries or affiliates shall be liable for the message if altered, changed or falsified.
    Ce message et toutes les pieces jointes (ci-apres le "message") sont confidentiels et etablis a l'intention exclusive de ses destinataires. Toute utilisation ou diffusion non autorisee est interdite. Tout message electronique est susceptible d'alteration. DxO Labs et ses filiales declinent toute responsabilite au titre de ce message s'il a ete altere, modifie ou falsifie.
  • Luke / Randall,

    Thanks for replying.  I did not want to embarrass Mr. Hillegass with
    my ignorance, but his book IS the one I am trying to follow.  I am
    currently working on his "To Do List" example in Chapter 6 (page 110).

    In my example, I have the following items in my App Controller class:

    Text Field (along with an IBOutlet)
    Button (along with an IBOutlet)
    Table View (along with an IBOutlet)
    Mutable Array instance variable

    My concern is whether or not the DIRECTION in which I CTRL-drag the
    objects.  For example, if do I drag from the Button object to the App
    Controller or do I CTRL-drag from the App Controller to the Button?

    I'm coming from a C# / .NET environment.  While there ARE visual
    design tools involved, it is much more manual.  For example, adding a
    Button to a Form creates the implmentation in the source file.  Double-
    clicking the control then creates the event handler for the object.
    Anything that you may want to do is handled programatically.

    Basically, since I cannot see what is happening under the hood, I'm
    beginning to second-guess that the calls will be made in the right
    direction.

    I hope that made sense.  Again, my apologies for such a noob-ish
    question.

    Thanx,
    Fred

    On Nov 17, 2008, at 1:56 PM, Randall Meadows wrote:

    > On Nov 17, 2008, at 11:09 AM, Greg Deward wrote:
    >
    >> Good afternoon!
    >>
    >> I am trying to learn Cocoa and am having difficulty remembering
    >> which direction to CTRL-drag controls to wire up the controls in
    >> Interface Builder.  For example, dragging from my button to my App
    >> Controller (NSObject) or vice versa.  Does anyone have a way to
    >> explain this that might make it stick?
    >
    > Aaron Hillegass, in his "Cocoa Programming for Mac OS X" book
    > explains it this way:
    >
    > "Now you are going to introduce some objects to each other....To
    > introduce one object to another, you will control-drag from the
    > object that needs to know to the object it needs to know about."
    >
    > So, for instance, a class needs to know about its NSButton outlet,
    > so you control-drag from the class to the NSButton in the window (to
    > set the IBOutlet).  The NSButton needs to know what method to call
    > when it is pressed, so you control-drag from the button to the class
    > (to set the IBAction).
    >
    > Or do what Luke said in his response... :)
    >
    >> It seems to me that a button should make a call to my App
    >> Controller when the click event is fired; therefore I should CTRL-
    >> drag FROM the button TO the NSObject. This would allow me to select
    >> the appropriate Received Action (ie, "doSomething", etc.").
    >
    > Yep, sounds like you have the basic gist of it...
    >
    >> However, if I need to do something with a text box (read from it)
    >> and a table view (insert an item), I should go the other way...
    >> since I'm going to fetch from the text field and then insert into
    >> the NSArray that is feeding the text view.
    >
    > But, what triggers the action of reading from the text field and
    > inserting that into the array that feeds the table (you said text,
    > but I assume that's a typo) view?  A button gets pressed? The user
    > presses Enter?  You set the action of the object that does that
    > action just as you would otherwise.
  • On Mon, Nov 17, 2008 at 11:36 AM, Greg Deward <greg.deward...> wrote:
    > Luke / Randall,
    >
    > Thanks for replying.  I did not want to embarrass Mr. Hillegass with my
    > ignorance, but his book IS the one I am trying to follow.  I am currently
    > working on his "To Do List" example in Chapter 6 (page 110).
    >
    > In my example, I have the following items in my App Controller class:
    >
    > Text Field (along with an IBOutlet)
    > Button (along with an IBOutlet)
    > Table View (along with an IBOutlet)
    > Mutable Array instance variable
    >
    > My concern is whether or not the DIRECTION in which I CTRL-drag the objects.
    > For example, if do I drag from the Button object to the App Controller or
    > do I CTRL-drag from the App Controller to the Button?

    Think of it this way: The object that you drag FROM is the object
    whose attributes you are changing.

    So, dragging from a button to its target is roughly equivalent to calling:
    [button setTarget: theTargetObject]

    and dragging from, for instance, a view controller to its view is
    equivalent to calling:
    [viewController setView: theView]

    --
    Clark S. Cox III
    <clarkcox3...>
  • On Nov 17, 2008, at 2:36 PM, Greg Deward wrote:
    > In my example, I have the following items in my App Controller class:
    >
    > Text Field (along with an IBOutlet)
    > Button (along with an IBOutlet)
    > Table View (along with an IBOutlet)
    > Mutable Array instance variable

    The technical term for these items is "instance variable," or "ivar"
    for short.  Your AppController class has instance variables of type
    NSTextField, NSButton, etc. which are named myTextField, myButton, or
    whatever made sense to you.

    You don't have ivars "along with" outlets.  An outlet *is* a
    particular kind of ivar.  It's an object reference that is declared in
    such a way that IB recognizes it and allows you to assign its value
    graphically in IB.  Typically the declaration has the modifier
    "IBOutlet" in front of it, as in:

    @interface AppController : NSObject {
        IBOutlet NSTextField *myTextField;
        ...
    }

    This is just a hint to IB to say "I want you to treat this ivar as an
    outlet."  The IBOutlet modifier has no other effect or purpose --
    indeed, it's just a macro that evaluates to nothing.

    > My concern is whether or not the DIRECTION in which I CTRL-drag the
    > objects.  For example, if do I drag from the Button object to the
    > App Controller or do I CTRL-drag from the App Controller to the
    > Button?

    Remember that an outlet is an object reference.  You can think of an
    object reference as a pointer that points TO another object.  When you
    Control-drag, imagine an arrowhead at the end of the line you're
    dragging.  You're making a connection FROM where you started the drag
    TO wherever you decide to drop that arrowhead.  As was explained
    earlier, you're making the FROM object aware of the TO object.

    In your specific example, you would drag FROM your AppController
    instance to each of the objects it needs to be aware of:

    "Hey app controller, I want >>this to be the text field your
    myTextField outlet points to."

    "Hey app controller, I want >>this to be the button your myButton
    outlet points to."

    Then when the nib is loaded at runtime, the app controller's ivars
    will point to those respective objects.

    To specify a button's target/action, you would say "Hey button
    [dragging from the button], I want >>this [dragging TO the app
    controller] to be your target."

    Similarly:

    "Hey text field, I want >>this to be your delegate."

    "Hey table view, I want >>this to be your data source."  (And again if
    you also want to set the table view's delegate.)

    --Andy
  • On Nov 17, 2008, at 1:46 PM, Andy Lee wrote:

    > You don't have ivars "along with" outlets.  An outlet *is* a
    > particular kind of ivar.  It's an object reference that is declared
    > in such a way that IB recognizes it and allows you to assign its
    > value graphically in IB.  Typically the declaration has the modifier
    > "IBOutlet" in front of it, as in:
    > @interface AppController : NSObject {
    > IBOutlet NSTextField *myTextField;
    > ...
    > }
    >
    Going forward, you're encouraged to declare outlets as follows:

    @interface AppController : NSObject {
        NSTextField *myTextField;
        ...
    }

    @property (nonatomic, retain) IBOutlet NSTextField *myTextField;

    <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
    es/chapter_5_section_3.html
    >

    mmalc
  • On Nov 17, 2008, at 3:06 PM, mmalcolm crawford wrote:

    > Going forward, you're encouraged to declare outlets as follows:
    > @interface AppController : NSObject {
    > NSTextField *myTextField;
    > ...
    > }
    > @property (nonatomic, retain) IBOutlet NSTextField *myTextField;
    >
    Jeff asked (posted with permission):

    "One remaining question. Are you expected to release the outlet when
    your
    controller is dealloc'd?  And did you have to prior to "properties"?
    I believed the answer to the latter was "no" but I'm prepared to be
    wrong on that.."

    Since the property is declared with the 'retain' attribute, the memory
    management semantics are made clear here.  Yes, you should release the
    outlet in dealloc.

    The problem heretofor was that the story was a mess -- whether or not
    you released the outlet was dependent upon what class File's Owner
    inherited from, and whether or not you had accessor methods.  The
    principal advantage with the property-based pattern is that memory
    management is consistent across all classes across all patterns.  It
    will also work on modern runtimes that use instance variable synthesis
    (where there may be no instance variable declaration with which to
    attach the IBOutlet).

    There may be some variation; if you have a delegate that may be
    connected using a delgate, then you may have:

    @interface AppController : NSObject {
      id delegate;
      ...
    }
    @property (nonatomic, assign) IBOutlet id delegate;

    although again use of a property declaration makes the memory
    management semantics clear (in this case you would of course not
    release delegate in dealloc).

    One other consideration, particularly in iPhone applications, is where
    you might have outlets to subviews of a main view that might be
    released in sime situations -- e.g. a UIViewController whose view is
    released in didReceiveMemoryWarning. To ensure that you don't prolong
    the lifetime of objects you got from the nib, you should set (use your
    accessor methods to) set those variables to nil in the relevant
    method, e.g.:

    @interface MyController : UIViewController {
      UILabel *label;
      ...
    }
    @property (nonatomic, retain) IBOutlet UILabel *label;

    then

    - (void)didReceiveMemoryWarning {
        self.label = nil;
        [super didReceiveMemoryWarning];
    }

    mmalc
  • On Nov 17, 2008, at 9:11 PM, mmalcolm crawford wrote:

    > One other consideration, particularly in iPhone applications, is
    > where you might have outlets to subviews of a main view that might
    > be released in sime situations -- e.g. a UIViewController whose view
    > is released in didReceiveMemoryWarning. To ensure that you don't
    > prolong the lifetime of objects you got from the nib, you should set
    > (use your accessor methods to) set those variables to nil in the
    > relevant method, e.g.:
    >
    > @interface MyController : UIViewController {
    > UILabel *label;
    > ...
    > }
    > @property (nonatomic, retain) IBOutlet UILabel *label;
    >
    > then
    >
    > - (void)didReceiveMemoryWarning {
    > self.label = nil;
    > [super didReceiveMemoryWarning];
    > }

    OK, this issue has come up for me very recently.  It appears that on
    iPhoneOS IBOutlets are retained, regardless of the presence of
    properties.  Even worse, in the presence of an assign property the
    outlet is still retained.  Whatever code is retaining the outlets
    never releases them.  So it seems that client code must release all
    outlets.

    The documentation on this is vague, with a lot of 'should's and not
    clear statements of what really happens.  Actually this isn't (only)
    related to didReceiveMemoryWarning (which I hadn't considered related
    to this problem until you raised it).

    Is this the way that things are supposed to work on iPhone OS?

    --
    Brian Stern
    <brians99...>
  • On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:

    > OK, this issue has come up for me very recently.  It appears that on
    > iPhoneOS IBOutlets are retained, regardless of the presence of
    > properties.  Even worse, in the presence of an assign property the
    > outlet is still retained.  Whatever code is retaining the outlets
    > never releases them.  So it seems that client code must release all
    > outlets.

    Seems to me that the outlets must have a retain count of at least one
    when they're unarchived, as though they were alloc'd. It makes sense
    that the programmer should have to manually release objects in
    dealloc. How else would it happen?

    Luke
  • On Nov 17, 2008, at 10:17 PM, Luke the Hiesterman wrote:

    >
    > On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:
    >
    >> OK, this issue has come up for me very recently.  It appears that
    >> on iPhoneOS IBOutlets are retained, regardless of the presence of
    >> properties.  Even worse, in the presence of an assign property the
    >> outlet is still retained.  Whatever code is retaining the outlets
    >> never releases them.  So it seems that client code must release all
    >> outlets.
    >
    > Seems to me that the outlets must have a retain count of at least
    > one when they're unarchived, as though they were alloc'd. It makes
    > sense that the programmer should have to manually release objects in
    > dealloc. How else would it happen?

    IBOutlets are not necessarily top level objects.  Most are simply
    views that happen to be in the view hierarchy.  There will typically
    be one top level object in an iPhone nib.  This will be the view that
    belongs to UIViewController.  It is the UIViewController base class
    that loads the nib.  As long as it retains that top level view then
    all the subviews will also be retained.  They should be released when
    the UIViewController releases its view outlet.

    Furthermore, NSBundle loadNibNamed:owner:options: on iPhone OS returns
    an array of the top level objects.  It would be trivial for the
    UIViewController base class object that is loading the nib to retain
    that array and of course release it in its dealloc.

    If user code doesn't retain the outlets I don't understand why user
    code should be releasing those objects.

    --
    Brian Stern
    <brians99...>
  • On Nov 17, 2008, at 7:46 PM, Brian Stern wrote:

    >
    > On Nov 17, 2008, at 10:17 PM, Luke the Hiesterman wrote:
    >
    >>
    >> On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:
    >>
    >>> OK, this issue has come up for me very recently.  It appears that
    >>> on iPhoneOS IBOutlets are retained, regardless of the presence of
    >>> properties.  Even worse, in the presence of an assign property the
    >>> outlet is still retained.  Whatever code is retaining the outlets
    >>> never releases them.  So it seems that client code must release
    >>> all outlets.
    >>
    >> Seems to me that the outlets must have a retain count of at least
    >> one when they're unarchived, as though they were alloc'd. It makes
    >> sense that the programmer should have to manually release objects
    >> in dealloc. How else would it happen?
    >
    > IBOutlets are not necessarily top level objects.  Most are simply
    > views that happen to be in the view hierarchy.  There will typically
    > be one top level object in an iPhone nib.  This will be the view
    > that belongs to UIViewController.  It is the UIViewController base
    > class that loads the nib.  As long as it retains that top level view
    > then all the subviews will also be retained.  They should be
    > released when the UIViewController releases its view outlet.

    Right, and view is a property of UIViewController. When you have your
    UIViewController release view, that is an example of the programmer
    releasing an outlet assigned from IB, which you seem to be arguing
    that the programmer shouldn't have to release objects given to it from
    IB.

    Luke

    >
    >
    > Furthermore, NSBundle loadNibNamed:owner:options: on iPhone OS
    > returns an array of the top level objects.  It would be trivial for
    > the UIViewController base class object that is loading the nib to
    > retain that array and of course release it in its dealloc.
    >
    > If user code doesn't retain the outlets I don't understand why user
    > code should be releasing those objects.
    >
    >
    > --
    > Brian Stern
    > <brians99...>
  • On Nov 17, 2008, at 10:53 PM, Luke the Hiesterman wrote:

    >
    > On Nov 17, 2008, at 7:46 PM, Brian Stern wrote:
    >
    >>
    >> On Nov 17, 2008, at 10:17 PM, Luke the Hiesterman wrote:
    >>
    >>>
    >>> On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:
    >>>
    >>>> OK, this issue has come up for me very recently.  It appears that
    >>>> on iPhoneOS IBOutlets are retained, regardless of the presence of
    >>>> properties.  Even worse, in the presence of an assign property
    >>>> the outlet is still retained.  Whatever code is retaining the
    >>>> outlets never releases them.  So it seems that client code must
    >>>> release all outlets.
    >>>
    >>> Seems to me that the outlets must have a retain count of at least
    >>> one when they're unarchived, as though they were alloc'd. It makes
    >>> sense that the programmer should have to manually release objects
    >>> in dealloc. How else would it happen?
    >>
    >> IBOutlets are not necessarily top level objects.  Most are simply
    >> views that happen to be in the view hierarchy.  There will
    >> typically be one top level object in an iPhone nib.  This will be
    >> the view that belongs to UIViewController.  It is the
    >> UIViewController base class that loads the nib.  As long as it
    >> retains that top level view then all the subviews will also be
    >> retained.  They should be released when the UIViewController
    >> releases its view outlet.
    >
    > Right, and view is a property of UIViewController. When you have
    > your UIViewController release view, that is an example of the
    > programmer releasing an outlet assigned from IB, which you seem to
    > be arguing that the programmer shouldn't have to release objects
    > given to it from IB.

    Top.  Level.  Object.

    Whatever code loads the nib is the owner of the array of top level
    objects and should retain them.  That object is UIViewController, not
    my subclass.

    At any rate.  The problem is that this is poorly documented.

    --
    Brian Stern
    <brians99...>
  • >>>> OK, this issue has come up for me very recently.  It appears that
    >>>> on iPhoneOS IBOutlets are retained, regardless of the presence of
    >>>> properties.  Even worse, in the presence of an assign property the
    >>>> outlet is still retained.  Whatever code is retaining the outlets
    >>>> never releases them.  So it seems that client code must release
    >>>> all outlets.
    >>>
    >>>
    >>> Seems to me that the outlets must have a retain count of at least
    >>> one when they're unarchived, as though they were alloc'd. It makes
    >>> sense that the programmer should have to manually release objects
    >>> in dealloc. How else would it happen?
    >>
    >>
    >> IBOutlets are not necessarily top level objects.  Most are simply
    >> views that happen to be in the view hierarchy.  There will typically
    >> be one top level object in an iPhone nib.  This will be the view
    >> that belongs to UIViewController.  It is the UIViewController base
    >> class that loads the nib.  As long as it retains that top level view
    >> then all the subviews will also be retained.  They should be
    >> released when the UIViewController releases its view outlet.
    >
    >
    > Right, and view is a property of UIViewController. When you have your
    > UIViewController release view, that is an example of the programmer
    > releasing an outlet assigned from IB, which you seem to be arguing
    > that the programmer shouldn't have to release objects given to it
    > from  IB.
    >
    > Luke
    >
    Exactly - most of the things you're hooking up in IB are your own
    objects, those outlets are just instance variables which are being set
    for you. It's your object, you have to deal with the lifetimes of the
    objects you refer to. I don't see why IB makes any difference, it's just
    calling setFoo: on some instance of your class, what you define setFoo
    to do is entirely up to you, but if it retains the argument, then you
    have to release it one day, in dealloc() would be the natural place.

    The iPhone version of nib unarchiving and hookup seemed very consistent
    to me, it makes use of properties or setFoo: if you have them, allowing
    you to manage objects any way you like.

    Perhaps the new @property() syntax makes it easy to forget about object
    lifetimes because it does the set/get/change automagically. These days
    when I add any property I go right to the dealloc method (and init if I
    have one) and ensure I've managed that property before I forget.
  • On Nov 17, 2008, at 11:05 PM, Roland King wrote:

    >
    >>>>> OK, this issue has come up for me very recently.  It appears
    >>>>> that  on iPhoneOS IBOutlets are retained, regardless of the
    >>>>> presence of  properties.  Even worse, in the presence of an
    >>>>> assign property the  outlet is still retained.  Whatever code is
    >>>>> retaining the outlets  never releases them.  So it seems that
    >>>>> client code must release  all outlets.
    >>>>
    >>>>
    >>>> Seems to me that the outlets must have a retain count of at
    >>>> least  one when they're unarchived, as though they were alloc'd.
    >>>> It makes  sense that the programmer should have to manually
    >>>> release objects  in dealloc. How else would it happen?
    >>>
    >>>
    >>> IBOutlets are not necessarily top level objects.  Most are simply
    >>> views that happen to be in the view hierarchy.  There will
    >>> typically  be one top level object in an iPhone nib.  This will be
    >>> the view  that belongs to UIViewController.  It is the
    >>> UIViewController base  class that loads the nib.  As long as it
    >>> retains that top level view  then all the subviews will also be
    >>> retained.  They should be  released when the UIViewController
    >>> releases its view outlet.
    >>
    >>
    >> Right, and view is a property of UIViewController. When you have
    >> your  UIViewController release view, that is an example of the
    >> programmer  releasing an outlet assigned from IB, which you seem to
    >> be arguing  that the programmer shouldn't have to release objects
    >> given to it from  IB.
    >>
    >> Luke
    >>
    > Exactly - most of the things you're hooking up in IB are your own
    > objects, those outlets are just instance variables which are being
    > set for you. It's your object, you have to deal with the lifetimes
    > of the objects you refer to. I don't see why IB makes any
    > difference, it's just calling setFoo: on some instance of your
    > class, what you define setFoo to do is entirely up to you, but if it
    > retains the argument, then you have to release it one day, in
    > dealloc() would be the natural place.
    >
    > The iPhone version of nib unarchiving and hookup seemed very
    > consistent to me, it makes use of properties or setFoo: if you have
    > them, allowing you to manage objects any way you like.
    >
    > Perhaps the new @property() syntax makes it easy to forget about
    > object lifetimes because it does the set/get/change automagically.
    > These days when I add any property I go right to the dealloc method
    > (and init if I have one) and ensure I've managed that property
    > before I forget.

    Yes, but this is exactly the point.  If I have no property for an
    Outlet it's still retained.  If I have a property for an outlet that
    is assign, and not retain the outlet is still retained, and I still
    must release it, even though I never retained it.

    When you say I can manage the outlets any way I like this is wrong.
    They are managed for me.  I want them to not be retained.  I don't
    have that option.

    Now that I understand this I can live with it.  But it still makes no
    sense to me.
  • On Nov 17, 2008, at 9:11 PM, mmalcolm crawford wrote:

    > One other consideration, particularly in iPhone applications, is
    > where you might have outlets to subviews of a main view that might
    > be released in sime situations -- e.g. a UIViewController whose view
    > is released in didReceiveMemoryWarning. To ensure that you don't
    > prolong the lifetime of objects you got from the nib, you should set
    > (use your accessor methods to) set those variables to nil in the
    > relevant method, e.g.:
    >
    > @interface MyController : UIViewController {
    > UILabel *label;
    > ...
    > }
    > @property (nonatomic, retain) IBOutlet UILabel *label;
    >
    > then
    >
    > - (void)didReceiveMemoryWarning {
    > self.label = nil;
    > [super didReceiveMemoryWarning];
    > }

    I think it makes more sense to release the Outlets in viewDidLoad.
    This way I only have to release them in one spot, not two.
  • On Nov 17, 2008, at 8:15 PM, Brian Stern wrote:

    > When you say I can manage the outlets any way I like this is wrong.
    > They are managed for me.  I want them to not be retained.  I don't
    > have that option.

    I never said this. I compared having objects unarchived from a nib to
    being alloc'd, where the retain count is initially set to 1.

    Luke
  • On Nov 17, 2008, at 8:17 PM, Brian Stern wrote:

    > I think it makes more sense to release the Outlets in viewDidLoad.

    Why would you be releasing outlets when the view just loaded?
    Generally releasing happens when you're ready for something to go
    away....
  • On Nov 17, 2008, at 11:20 PM, Luke the Hiesterman wrote:

    >
    > On Nov 17, 2008, at 8:17 PM, Brian Stern wrote:
    >
    >> I think it makes more sense to release the Outlets in viewDidLoad.
    >
    > Why would you be releasing outlets when the view just loaded?
    > Generally releasing happens when you're ready for something to go
    > away....

    There is an extra retain on the Outlets.  It is unneeded.  The outlets
    are sufficiently retained by the view hierarchy.

    Either I have to release in both dealloc and in
    didReceiveMemoryWarning, or I can have them in viewDidLoad.

    Release also is sent when you transfer ownership of an object to
    another object.  I don't wish to have ownership of the outlets.  They
    can be owned by the view hierarchy.  So if I release them in
    viewDidLoad then I don't have to release them in two other places,
    which is obviously error prone.

    Don't you find it odd that you need to release outlets in
    didReceiveMemoryWarning?
  • >
    > Yes, but this is exactly the point.  If I have no property for an
    > Outlet it's still retained.  If I have a property for an outlet that
    > is assign, and not retain the outlet is still retained, and I still
    > must release it, even though I never retained it.
    >
    > When you say I can manage the outlets any way I like this is wrong.
    > They are managed for me.  I want them to not be retained.  I don't
    > have that option.
    >
    > Now that I understand this I can live with it.  But it still makes no
    > sense to me.
    > _______________________________________________

    That's not what the documentation says and it's not my experience
    either. The documentation says (section titled NIB Object Retention)
    that each object in the NIB file is created with a retain count of 1 and
    then autoreleased. Then they are hooked up using setValue:forKey: which
    uses the setter method if it exists. It also explicitly tells you that
    if you don't retain the array of top-level objects you're going to lose
    them.

    So if you have an outlet which is assign, and the setter method is
    correct, the object will be created with retain count of 1,
    autoreleased, then the setter method will be called and assign it (no
    retain) and you do not have to release it. Why do you think that you do?

    I've done this, I have this exact patten in some of my iPhone code, I
    have a delegate property which is assign and it is assigned and it goes
    away when it's supposed to go away.
  • On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:

    > On Nov 17, 2008, at 9:11 PM, mmalcolm crawford wrote:
    >
    >> One other consideration, particularly in iPhone applications, is
    >> where you might have outlets to subviews of a main view that might
    >> be released in sime situations -- e.g. a UIViewController whose
    >> view is released in didReceiveMemoryWarning. To ensure that you
    >> don't prolong the lifetime of objects you got from the nib, you
    >> should set (use your accessor methods to) set those variables to
    >> nil in the relevant method, e.g.:
    >>
    >> @interface MyController : UIViewController {
    >> UILabel *label;
    >> ...
    >> }
    >> @property (nonatomic, retain) IBOutlet UILabel *label;
    >>
    >> then
    >>
    >> - (void)didReceiveMemoryWarning {
    >> self.label = nil;
    >> [super didReceiveMemoryWarning];
    >> }
    >
    > OK, this issue has come up for me very recently.  It appears that on
    > iPhoneOS IBOutlets are retained, regardless of the presence of
    > properties.
    >
    No, on iPhone outlets are consistently *not* retained -- which is
    precisely why you do need to retain top-level objects on iPhone. But
    absent accessor methods, connections are made using KVC...
    This is documented here:
    <http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Lo
    adingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000
    051i-CH4-SW6
    >

    > Even worse, in the presence of an assign property the outlet is
    > still retained.  Whatever code is retaining the outlets never
    > releases them.  So it seems that client code must release all outlets.
    >
    As I stated originally, following the pattern I describe above makes
    memory management consistent in all situations.

    > The documentation on this is vague, with a lot of 'should's and not
    > clear statements of what really happens.
    >

    The documentation at    <http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Lo
    adingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000
    051i-CH4-SW6
    > is explicit, there are just many different situations to consider
    if you don't follow the property pattern.

    mmalc

    > Actually this isn't (only) related to didReceiveMemoryWarning (which
    > I hadn't considered related to this problem until you raised it).
  • On Nov 17, 2008, at 11:35 PM, Roland King wrote:

    >
    >>
    >> Yes, but this is exactly the point.  If I have no property for an
    >> Outlet it's still retained.  If I have a property for an outlet
    >> that  is assign, and not retain the outlet is still retained, and I
    >> still  must release it, even though I never retained it.
    >>
    >> When you say I can manage the outlets any way I like this is
    >> wrong.  They are managed for me.  I want them to not be retained.
    >> I don't  have that option.
    >>
    >> Now that I understand this I can live with it.  But it still makes
    >> no  sense to me.
    >> _______________________________________________
    >
    > That's not what the documentation says and it's not my experience
    > either. The documentation says (section titled NIB Object Retention)
    > that each object in the NIB file is created with a retain count of 1
    > and then autoreleased. Then they are hooked up using
    > setValue:forKey: which uses the setter method if it exists. It also
    > explicitly tells you that if you don't retain the array of top-level
    > objects you're going to lose them.
    >
    > So if you have an outlet which is assign, and the setter method is
    > correct, the object will be created with retain count of 1,
    > autoreleased, then the setter method will be called and assign it
    > (no retain) and you do not have to release it. Why do you think that
    > you do?
    >
    > I've done this, I have this exact patten in some of my iPhone code,
    > I have a delegate property which is assign and it is assigned and it
    > goes away when it's supposed to go away.

    OK.  The reason I believe that is because I fixed a massive memory
    leak a couple days ago that I tracked down to this issue.  I built a
    simple test application that demonstrates that outlets that have no
    properties or have assign properties are retained anyway and must be
    released.

    Here's my test project:

    http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip

    There are three labels that are outlets.  One has a retain property,
    one an assign property, and the third no property.  Unless they are
    released they are never dealloced.  All three act the same.

    --
    Brian Stern
    <brians99...>
  • On Nov 17, 2008, at 8:05 PM, Roland King wrote:

    > The iPhone version of nib unarchiving and hookup seemed very
    > consistent to me, it makes use of properties or setFoo: if you have
    > them, allowing you to manage objects any way you like.
    >
    This applies to both iPhone and Mac OS X/desktop.
    This is why using properties simplifies matters...

    mmalc
  • On Nov 17, 2008, at 8:17 PM, Brian Stern wrote:

    > I think it makes more sense to release the Outlets in viewDidLoad.
    > This way I only have to release them in one spot, not two.
    >
    No, it doesn't.
    There is no sense at all in releasing outlets in viewDidLoad.
    Follow the pattern I described and it's consistent...

    mmalc
  • On Nov 17, 2008, at 8:34 PM, Brian Stern wrote:

    > Don't you find it odd that you need to release outlets in
    > didReceiveMemoryWarning?
    >
    Not at all -- assuming that you have a reference -- strong or weak --
    to an item in the user interface, you want to make sure you break it
    if the view is supposed to disappear.
    If you have a strong reference you want to make sure that the item is
    disposed of when the other items from the nib go away; if you have a
    weak reference you want to make sure you don't send a message to a
    deallocated object (it'll go when the view goes...).

    mmalc
  • On Nov 17, 2008, at 11:58 PM, mmalcolm crawford wrote:

    >
    > On Nov 17, 2008, at 8:34 PM, Brian Stern wrote:
    >
    >> Don't you find it odd that you need to release outlets in
    >> didReceiveMemoryWarning?
    >>
    > Not at all -- assuming that you have a reference -- strong or weak
    > -- to an item in the user interface, you want to make sure you break
    > it if the view is supposed to disappear.
    > If you have a strong reference you want to make sure that the item
    > is disposed of when the other items from the nib go away; if you
    > have a weak reference you want to make sure you don't send a message
    > to a deallocated object (it'll go when the view goes...).

    UIViewController isn't guaranteed to release the view.  It only does
    this if the view isn't visible, based on its own heuristics.  My
    subclass has no real way to know if the view will be released or not.

    If I release the outlets in viewDidLoad then I don't have this
    problem.  My code has no interest in maintaining a strong reference to
    its outlets.  The view hierarchy can do that just fine.

    --
    Brian Stern
    <brians99...>
  • On Nov 17, 2008, at 11:51 PM, mmalcolm crawford wrote:

    >
    > On Nov 17, 2008, at 7:12 PM, Brian Stern wrote:
    >
    >> On Nov 17, 2008, at 9:11 PM, mmalcolm crawford wrote:
    >>
    >>> One other consideration, particularly in iPhone applications, is
    >>> where you might have outlets to subviews of a main view that might
    >>> be released in sime situations -- e.g. a UIViewController whose
    >>> view is released in didReceiveMemoryWarning. To ensure that you
    >>> don't prolong the lifetime of objects you got from the nib, you
    >>> should set (use your accessor methods to) set those variables to
    >>> nil in the relevant method, e.g.:
    >>>
    >>> @interface MyController : UIViewController {
    >>> UILabel *label;
    >>> ...
    >>> }
    >>> @property (nonatomic, retain) IBOutlet UILabel *label;
    >>>
    >>> then
    >>>
    >>> - (void)didReceiveMemoryWarning {
    >>> self.label = nil;
    >>> [super didReceiveMemoryWarning];
    >>> }
    >>
    >> OK, this issue has come up for me very recently.  It appears that
    >> on iPhoneOS IBOutlets are retained, regardless of the presence of
    >> properties.
    >>
    > No, on iPhone outlets are consistently *not* retained -- which is
    > precisely why you do need to retain top-level objects on iPhone. But
    > absent accessor methods, connections are made using KVC...
    > This is documented here:
    > <http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Lo
    adingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000
    051i-CH4-SW6
    > >

    That's the vague documentation that I referred to.  What you're
    telling me is that where it says should in that paragraph it really
    means must.  OK, that's what I figured out a few days ago.

    Where it says that it "retains the object by default if no setter
    method is available", that seems to contradict what you say about
    outlets not being retained.  Actually I didn't really absorb that
    statement before.  It means that if there's no property then the
    outlet will be retained.  OK.

    My experience with the assign property is contrary to what the docs
    seem to be saying.  I think the outlet is retained even if there is an
    assign property.

    > As I stated originally, following the pattern I describe above makes
    > memory management consistent in all situations.

    I simply don't need properties for all my Outlets, except for this
    issue.  I also don't really like making all my outlets implicitly
    public.  But I'm forced to do that.

    --
    Brian Stern
    <brians99...>
  • Brian Stern wrote:

    >
    > On Nov 17, 2008, at 11:35 PM, Roland King wrote:
    >
    >>
    >>>
    >>> Yes, but this is exactly the point.  If I have no property for an
    >>> Outlet it's still retained.  If I have a property for an outlet
    >>> that  is assign, and not retain the outlet is still retained, and I
    >>> still  must release it, even though I never retained it.
    >>>
    >>> When you say I can manage the outlets any way I like this is
    >>> wrong.  They are managed for me.  I want them to not be retained.
    >>> I don't  have that option.
    >>>
    >>> Now that I understand this I can live with it.  But it still makes
    >>> no  sense to me.
    >>> _______________________________________________
    >>
    >>
    >> That's not what the documentation says and it's not my experience
    >> either. The documentation says (section titled NIB Object Retention)
    >> that each object in the NIB file is created with a retain count of 1
    >> and then autoreleased. Then they are hooked up using
    >> setValue:forKey: which uses the setter method if it exists. It also
    >> explicitly tells you that if you don't retain the array of top-level
    >> objects you're going to lose them.
    >>
    >> So if you have an outlet which is assign, and the setter method is
    >> correct, the object will be created with retain count of 1,
    >> autoreleased, then the setter method will be called and assign it
    >> (no retain) and you do not have to release it. Why do you think that
    >> you do?
    >>
    >> I've done this, I have this exact patten in some of my iPhone code,
    >> I have a delegate property which is assign and it is assigned and it
    >> goes away when it's supposed to go away.
    >
    >
    >
    > OK.  The reason I believe that is because I fixed a massive memory
    > leak a couple days ago that I tracked down to this issue.  I built a
    > simple test application that demonstrates that outlets that have no
    > properties or have assign properties are retained anyway and must be
    > released.
    >
    > Here's my test project:
    >
    > http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    >
    >
    > There are three labels that are outlets.  One has a retain property,
    > one an assign property, and the third no property.  Unless they are
    > released they are never dealloced.  All three act the same.
    >
    I'm a bit limited at work, no Mac here, so I took a look with wordpad ..
    how nice.

    You've defined the actual label pointers as IBOutlet, like this

        IBOutlet MyLabel* mLabel1;

    and then called the properties label1 etc.

    in your .h file. When you hook them up in IB (I can't open that here so
    I'm afraid I can't look) what is the name of the thing you bind to,
    label1 or mLabel1? I think you'll find it's mLabel1 right? I believe
    what you're doing is accessing the variables DIRECTLY in each binding
    because you have defined those at outlets, not the properties, and in
    that case yes they get retained as you know and as the documentation says.

    What I think you wanted was this

        MyLabel *mLabel1;

        @property( nonatomic, assign ) IBOutlet MyLabel *label1;

    to define the PROPERTY as the outlet, not the variable.

    I think if you'd written your own setters/getters instead of
    synthesizing them, as I sometimes do when I really don't know who the
    hell is calling me and when, you'd find they didn't get called. I
    sometimes think that |accessInstanceVariablesDirectly is evil and should
    be turned off.

    I started off using properties and calling them something different from
    variables because I was paranoid I'd access them directly, I've sort of
    stopped that now as I mostly remember not to do that, but I can
    understand why you'd want them differently named.

    Roland
    |
  • On Nov 17, 2008, at 8:53 PM, Brian Stern wrote:

    > Here's my test project:
    > http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    > There are three labels that are outlets.  One has a retain property,
    > one an assign property, and the third no property.  Unless they are
    > released they are never dealloced.  All three act the same.
    >
    It would help if you declared/connected your outlets correctly...

    If you declare a property:

    @property (nonatomic, assign) MyLabel *label1;

    but make the connection in IB to mLabel1, then the property accessor
    isn't used.  So the outlet is set using setValue:forKey:.  Which
    results in the value being retained, precisely as described in the
    documentation...

    <http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Lo
    adingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000
    051i-CH4-SW6
    >

    If you declare the the properties as I described:

    @interface ViewControllerOne : UIViewController
    {
        MyLabel*    mLabel1;
        MyLabel*    mLabel2;
        IBOutlet MyLabel*    mLabel3;
    }

    @property (nonatomic, assign) IBOutlet MyLabel *mLabel1;
    @property (nonatomic, retain) IBOutlet MyLabel *mLabel2;
    // No property for label3

    then you'll get the behaviour I described...

    mmalc
  • On Nov 17, 2008, at 9:10 PM, Brian Stern wrote:

    > I simply don't need properties for all my Outlets, except for this
    > issue.  I also don't really like making all my outlets implicitly
    > public.  But I'm forced to do that.

    You can use the readonly option for your properties. Alternatively,
    you can can declare a private setter.
  • On Nov 17, 2008, at 9:11 PM, Roland King wrote:

    > I'm a bit limited at work, no Mac here, so I took a look with
    > wordpad .. how nice.
    >
    > You've defined the actual label pointers as IBOutlet, like this
    >
    > IBOutlet MyLabel* mLabel1;
    >
    > and then called the properties label1 etc.
    >
    > in your .h file. When you hook them up in IB (I can't open that here
    > so I'm afraid I can't look) what is the name of the thing you bind
    > to, label1 or mLabel1? I think you'll find it's mLabel1 right? I
    > believe what you're doing is accessing the variables DIRECTLY in
    > each binding because you have defined those at outlets, not the
    > properties, and in that case yes they get retained as you know and
    > as the documentation says.

    Roland is correct. You've hooked up IB directly to the instance
    variables.
  • On Nov 18, 2008, at 12:11 AM, Roland King wrote:

    > Brian Stern wrote:
    >
    >>
    >> On Nov 17, 2008, at 11:35 PM, Roland King wrote:
    >>
    >>>
    >>>>
    >>>> Yes, but this is exactly the point.  If I have no property for
    >>>> an  Outlet it's still retained.  If I have a property for an
    >>>> outlet  that  is assign, and not retain the outlet is still
    >>>> retained, and I  still  must release it, even though I never
    >>>> retained it.
    >>>>
    >>>> When you say I can manage the outlets any way I like this is
    >>>> wrong.  They are managed for me.  I want them to not be
    >>>> retained.  I don't  have that option.
    >>>>
    >>>> Now that I understand this I can live with it.  But it still
    >>>> makes  no  sense to me.
    >>>> _______________________________________________
    >>>
    >>>
    >>> That's not what the documentation says and it's not my experience
    >>> either. The documentation says (section titled NIB Object
    >>> Retention)  that each object in the NIB file is created with a
    >>> retain count of 1  and then autoreleased. Then they are hooked up
    >>> using  setValue:forKey: which uses the setter method if it exists.
    >>> It also  explicitly tells you that if you don't retain the array
    >>> of top-level  objects you're going to lose them.
    >>>
    >>> So if you have an outlet which is assign, and the setter method
    >>> is  correct, the object will be created with retain count of 1,
    >>> autoreleased, then the setter method will be called and assign it
    >>> (no retain) and you do not have to release it. Why do you think
    >>> that  you do?
    >>>
    >>> I've done this, I have this exact patten in some of my iPhone
    >>> code,  I have a delegate property which is assign and it is
    >>> assigned and it  goes away when it's supposed to go away.
    >>
    >>
    >>
    >> OK.  The reason I believe that is because I fixed a massive memory
    >> leak a couple days ago that I tracked down to this issue.  I built
    >> a  simple test application that demonstrates that outlets that have
    >> no  properties or have assign properties are retained anyway and
    >> must be  released.
    >>
    >> Here's my test project:
    >>
    >> http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    >>
    >> There are three labels that are outlets.  One has a retain
    >> property,  one an assign property, and the third no property.
    >> Unless they are  released they are never dealloced.  All three act
    >> the same.
    >>
    > in your .h file. When you hook them up in IB (I can't open that here
    > so I'm afraid I can't look) what is the name of the thing you bind
    > to, label1 or mLabel1? I think you'll find it's mLabel1 right? I
    > believe what you're doing is accessing the variables DIRECTLY in
    > each binding because you have defined those at outlets, not the
    > properties, and in that case yes they get retained as you know and
    > as the documentation says.
    >
    > What I think you wanted was this
    >
    > MyLabel *mLabel1;
    >
    > @property( nonatomic, assign ) IBOutlet MyLabel *label1;
    >
    > to define the PROPERTY as the outlet, not the variable.
    >

    You're right.  I guess I didn't know there was a difference in the
    semantics based on the position of the IBOutlet.

    In the end though I'm still pretty much forced to have properties for
    these outlets even though I don't want them.

    --
    Brian Stern
    <brians99...>
  • > If you declare a property:
    >
    > @property (nonatomic, assign) MyLabel *label1;
    >
    > but make the connection in IB to mLabel1, then the property accessor
    > isn't used.  So the outlet is set using setValue:forKey:.  Which
    > results in the value being retained, precisely as described in the
    > documentation...
    >
    >
    <http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptu>
    al/LoadingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/
    > uid/10000051i-CH4-SW6

    How about:

    http://developer.apple.com/samplecode/CacheInfo-MacOSX/listing1.html

    (for example) which has the IBOutlet tag on the instance variables
    rather than the properties; I'll bet its different because properties
    and instance vars have the same name, isn't it?

    (Note, this isn't the only one I've seen this pattern in, its just the
    first that came to hand)

    That example declares dozens of IBOutlet's, whose properties are
    (nonatomic,retain) and doesn't release any of them in its dealloc.
  • On Nov 17, 2008, at 10:12 PM, Brian Stern wrote:

    >
    > On Nov 17, 2008, at 9:11 PM, mmalcolm crawford wrote:
    >
    >> One other consideration, particularly in iPhone applications, is
    >> where you might have outlets to subviews of a main view that might
    >> be released in sime situations -- e.g. a UIViewController whose
    >> view is released in didReceiveMemoryWarning. To ensure that you
    >> don't prolong the lifetime of objects you got from the nib, you
    >> should set (use your accessor methods to) set those variables to
    >> nil in the relevant method, e.g.:
    >>
    >> @interface MyController : UIViewController {
    >> UILabel *label;
    >> ...
    >> }
    >> @property (nonatomic, retain) IBOutlet UILabel *label;
    >>
    >> then
    >>
    >> - (void)didReceiveMemoryWarning {
    >> self.label = nil;
    >> [super didReceiveMemoryWarning];
    >> }
    >
    > OK, this issue has come up for me very recently.  It appears that on
    > iPhoneOS IBOutlets are retained, regardless of the presence of
    > properties.
    > Even worse, in the presence of an assign property the outlet is
    > still retained.  Whatever code is retaining the outlets never
    > releases them.  So it seems that client code must release all outlets.

    The above statements are not true. On the iPhone, outlets are
    connected with setValue:forKeyPath:, and no explicit retention is done
    by the NIB unarchiving code. It maybe true that the objects are
    retained in some other fashion, independent of outlets. For example,
    when the MainWindow.nib is loaded by UIApplication, UIApplication
    explicitly retains the returned top level objects. That's a property
    of UIApplication, and doesn't really have anything to do with NIB
    loading in general. In the future, other nib loading classes may
    choose to do the same thing. If this is the situation you're referring
    to, and you're sending your outlet objects an extra release message,
    you're over releasing them.

    The solution to a memory leak should never be an unbalanced release.
    You should use instruments and object alloc to determine exactly where
    the unbalanced retain is, and then balance it correctly. If you find a
    leak in framework code, you should file a bug, and you may consider
    over releasing it on your end for ballence, but if you choose to do
    that, you should do it with extreme caution. If there really is a leak
    in the framework code, then when it's fixed, you're unbalanced
    releases will start causing crashes.

    > The documentation on this is vague, with a lot of 'should's and not
    > clear statements of what really happens.

    If you ask specific questions about specific pieces of documentation,
    I'm sure that many readers would be happy to help you.

    Jon Hess

    > Actually this isn't (only) related to didReceiveMemoryWarning (which
    > I hadn't considered related to this problem until you raised it).
    >
    > Is this the way that things are supposed to work on iPhone OS?
    >
    >
    > --
    > Brian Stern
    > <brians99...>
  • On Nov 18, 2008, at 12:13 AM, mmalcolm crawford wrote:

    >
    > On Nov 17, 2008, at 8:53 PM, Brian Stern wrote:
    >
    >> Here's my test project:
    >> http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    >> There are three labels that are outlets.  One has a retain
    >> property, one an assign property, and the third no property.
    >> Unless they are released they are never dealloced.  All three act
    >> the same.
    >>
    > It would help if you declared/connected your outlets correctly...
    >
    > //...
    >
    > then you'll get the behaviour I described...

    OK, fair enough.

    You didn't address my other point regarding the memory warnings.  If
    the view controller is visible then it won't release the view
    hierarchy.  Your suggested code will null the outlet even though it
    still exists, resulting in bugs in some cases.

    --
    Brian Stern
    <brians99...>
  • >> Perhaps the new @property() syntax makes it easy to forget about
    >> object lifetimes because it does the set/get/change automagically.
    >> These days when I add any property I go right to the dealloc method
    >> (and init if I have one) and ensure I've managed that property
    >> before I forget.
    >
    > Yes, but this is exactly the point.  If I have no property for an
    > Outlet it's still retained.

    Hey Brian -

    Outlets for iPhone OS are established by calling setValue:forKeyPath:.
    The behavior of setValue:forKeyPath: is that if a setter exists, it is
    called. If a setter does not exist, the instance variable is looked up
    and set directly, and if it is an object, it is retained. This means
    that for IBOutlets, with no setters, they're retained in iPhone OS.
    This is different from Mac OS X. If you're writing code on both
    platforms, or are planning to, you should always use properties on
    both platforms since it makes the decision to retain outlets explicit
    and obvious.

    Jon Hess
  • On Nov 18, 2008, at 1:11 PM, Roland King wrote:

    > Brian Stern wrote:
    >
    >>
    >> On Nov 17, 2008, at 11:35 PM, Roland King wrote:
    >>
    >>>
    >>>>
    >>>> Yes, but this is exactly the point.  If I have no property for
    >>>> an  Outlet it's still retained.  If I have a property for an
    >>>> outlet  that  is assign, and not retain the outlet is still
    >>>> retained, and I  still  must release it, even though I never
    >>>> retained it.
    >>>>
    >>>> When you say I can manage the outlets any way I like this is
    >>>> wrong.  They are managed for me.  I want them to not be
    >>>> retained.  I don't  have that option.
    >>>>
    >>>> Now that I understand this I can live with it.  But it still
    >>>> makes  no  sense to me.
    >>>> _______________________________________________
    >>>
    >>>
    >>> That's not what the documentation says and it's not my experience
    >>> either. The documentation says (section titled NIB Object
    >>> Retention)  that each object in the NIB file is created with a
    >>> retain count of 1  and then autoreleased. Then they are hooked up
    >>> using  setValue:forKey: which uses the setter method if it exists.
    >>> It also  explicitly tells you that if you don't retain the array
    >>> of top-level  objects you're going to lose them.
    >>>
    >>> So if you have an outlet which is assign, and the setter method
    >>> is  correct, the object will be created with retain count of 1,
    >>> autoreleased, then the setter method will be called and assign it
    >>> (no retain) and you do not have to release it. Why do you think
    >>> that  you do?
    >>>
    >>> I've done this, I have this exact patten in some of my iPhone
    >>> code,  I have a delegate property which is assign and it is
    >>> assigned and it  goes away when it's supposed to go away.
    >>
    >>
    >>
    >> OK.  The reason I believe that is because I fixed a massive memory
    >> leak a couple days ago that I tracked down to this issue.  I built
    >> a  simple test application that demonstrates that outlets that have
    >> no  properties or have assign properties are retained anyway and
    >> must be  released.
    >>
    >> Here's my test project:
    >>
    >> http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    >>
    >> There are three labels that are outlets.  One has a retain
    >> property,  one an assign property, and the third no property.
    >> Unless they are  released they are never dealloced.  All three act
    >> the same.
    >>
    > I'm a bit limited at work, no Mac here, so I took a look with
    > wordpad .. how nice.
    >
    > You've defined the actual label pointers as IBOutlet, like this
    >
    > IBOutlet MyLabel* mLabel1;
    >
    > and then called the properties label1 etc.
    >
    > in your .h file. When you hook them up in IB (I can't open that here
    > so I'm afraid I can't look) what is the name of the thing you bind
    > to, label1 or mLabel1? I think you'll find it's mLabel1 right? I
    > believe what you're doing is accessing the variables DIRECTLY in
    > each binding because you have defined those at outlets, not the
    > properties, and in that case yes they get retained as you know and
    > as the documentation says.
    >
    > What I think you wanted was this
    >
    > MyLabel *mLabel1;
    >
    > @property( nonatomic, assign ) IBOutlet MyLabel *label1;
    >
    > to define the PROPERTY as the outlet, not the variable.
    >
    > I think if you'd written your own setters/getters instead of
    > synthesizing them, as I sometimes do when I really don't know who
    > the hell is calling me and when, you'd find they didn't get called.
    > I sometimes think that |accessInstanceVariablesDirectly is evil and
    > should be turned off.
    >
    > I started off using properties and calling them something different
    > from variables because I was paranoid I'd access them directly, I've
    > sort of stopped that now as I mostly remember not to do that, but I
    > can understand why you'd want them differently named.

    Normally instance variables and properties share the same name, so it
    doesn't matter to Interface Builder where the 'IBOutlet' text appears.
    If you're going to give your instance variables different names
    though, you need to put the IBOutlet qualifier on the property if you
    want it to be used.

    In the above example, Interface Builder is going to use '[obj
    setValue:someLabel forKeyPath:@"mLabel"]' which won't result in the
    setter being used. The problem is the 'mLabel' for the keyPath instead
    of 'label'.

    The only thing that determines if Interface Builder uses a setter, or
    accesses iVars directly is the presence of the setter, and the name of
    the outlet. The name of the outlet is used as the keyPath in
    setValue:forKeyPath:. The name of the outlet is the name of the
    property or instance variable the IBOutlet modifier appears next to.
    Interface Builder always calls setValue:forKeyPath:.

    Jon Hess

    >
    >
    > Roland
    > |
  • On Nov 18, 2008, at 12:34 AM, Jonathan Hess wrote:

    >
    > The solution to a memory leak should never be an unbalanced release.

    What I did to fix this was to add all of the properties to all of the
    outlets so they'd all be retained through those properties.  Then I
    added all the releases to all the deallocs to match those retains.

    --
    Brian Stern
    <brians99...>
  • > I simply don't need properties for all my Outlets, except for this
    > issue.  I also don't really like making all my outlets implicitly
    > public.  But I'm forced to do that.

    Here's one way to avoid making your outlets public:

    // Header
    @interface MyClass : NSObject {
        @private
        IBOutlet UILabel *myLabel;
    }
    @end

    // Implementation
    @implementation MyClass
    - (void)setMyLabel:(UILabel *)myLabel {
        myLabel = label;
    }
    @end

    You get non-retained outlets, and it's still explicit and obvious. You
    can create many other variations of this. For example, you can use
    @property and @synthesize in only the implementation file. The most
    important thing to remember is that IB calls setValue:forKeyPath: with
    a key path that is equal to the name of your outlet. You can read
    about key value coding here: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Ke
    yValueCoding.html


    Compiled in mail -
    Jon Hess
  • On Nov 18, 2008, at 12:32 AM, Brian Stern wrote:

    >
    > On Nov 18, 2008, at 12:11 AM, Roland King wrote:
    >
    >> Brian Stern wrote:
    >>
    >>>
    >>> On Nov 17, 2008, at 11:35 PM, Roland King wrote:
    >>>
    >>>>
    >>>>>
    >>>>> Yes, but this is exactly the point.  If I have no property for
    >>>>> an  Outlet it's still retained.  If I have a property for an
    >>>>> outlet  that  is assign, and not retain the outlet is still
    >>>>> retained, and I  still  must release it, even though I never
    >>>>> retained it.
    >>>>>
    >>>>> When you say I can manage the outlets any way I like this is
    >>>>> wrong.  They are managed for me.  I want them to not be
    >>>>> retained.  I don't  have that option.
    >>>>>
    >>>>> Now that I understand this I can live with it.  But it still
    >>>>> makes  no  sense to me.
    >>>>> _______________________________________________
    >>>>
    >>>>
    >>>> That's not what the documentation says and it's not my
    >>>> experience  either. The documentation says (section titled NIB
    >>>> Object Retention)  that each object in the NIB file is created
    >>>> with a retain count of 1  and then autoreleased. Then they are
    >>>> hooked up using  setValue:forKey: which uses the setter method if
    >>>> it exists. It also  explicitly tells you that if you don't retain
    >>>> the array of top-level  objects you're going to lose them.
    >>>>
    >>>> So if you have an outlet which is assign, and the setter method
    >>>> is  correct, the object will be created with retain count of 1,
    >>>> autoreleased, then the setter method will be called and assign
    >>>> it  (no retain) and you do not have to release it. Why do you
    >>>> think that  you do?
    >>>>
    >>>> I've done this, I have this exact patten in some of my iPhone
    >>>> code,  I have a delegate property which is assign and it is
    >>>> assigned and it  goes away when it's supposed to go away.
    >>>
    >>>
    >>>
    >>> OK.  The reason I believe that is because I fixed a massive
    >>> memory  leak a couple days ago that I tracked down to this issue.
    >>> I built a  simple test application that demonstrates that outlets
    >>> that have no  properties or have assign properties are retained
    >>> anyway and must be  released.
    >>>
    >>> Here's my test project:
    >>>
    >>> http://bellsouthpwp2.net/b/r/brians99/projects/TestPropertiesAndOutlets.zip
    >>>
    >>> There are three labels that are outlets.  One has a retain
    >>> property,  one an assign property, and the third no property.
    >>> Unless they are  released they are never dealloced.  All three act
    >>> the same.
    >>>
    >> in your .h file. When you hook them up in IB (I can't open that
    >> here so I'm afraid I can't look) what is the name of the thing you
    >> bind to, label1 or mLabel1? I think you'll find it's mLabel1 right?
    >> I believe what you're doing is accessing the variables DIRECTLY in
    >> each binding because you have defined those at outlets, not the
    >> properties, and in that case yes they get retained as you know and
    >> as the documentation says.
    >>
    >> What I think you wanted was this
    >>
    >> MyLabel *mLabel1;
    >>
    >> @property( nonatomic, assign ) IBOutlet MyLabel *label1;
    >>
    >> to define the PROPERTY as the outlet, not the variable.
    >>
    >
    > You're right.  I guess I didn't know there was a difference in the
    > semantics based on the position of the IBOutlet.

    I know I'm repeating myself, but I just want to be clear. The problem
    here isn't the position of 'IBOutlet' the problem is that the instance
    variable and property have different names. Referring to the outlet
    'mLabel' is different than referring to the outlet 'label'. One will
    result in looking for a setter called 'setMLabel:' and the other will
    result in looking for a setter named 'setLabel:' If the property and
    the instance variable had the same name, it wouldn't matter where you
    placed the IBOutlet modifier.

    Jon Hess

    >
    >
    > In the end though I'm still pretty much forced to have properties
    > for these outlets even though I don't want them.
    >
    >
    > --
    > Brian Stern
    > <brians99...>
  • On Nov 18, 2008, at 12:35 AM, Jonathan Hess wrote:
    >
    > Normally instance variables and properties share the same name,

    Normally in your code maybe, not mine.

    > so it doesn't matter to Interface Builder where the 'IBOutlet' text
    > appears. If you're going to give your instance variables different
    > names though, you need to put the IBOutlet qualifier on the property
    > if you want it to be used.

    I guess I just had a perfect storm of issues that made it appear that
    things were working differently from the way they were working.  My
    properties, though present, were ignored. The fact that it works
    differently from Mac OS makes it worse.

    Thanks for the help guys.

    --
    Brian Stern
    <brians99...>
  • On Nov 18, 2008, at 12:35 AM, Jonathan Hess wrote:

    >>> Perhaps the new @property() syntax makes it easy to forget about
    >>> object lifetimes because it does the set/get/change automagically.
    >>> These days when I add any property I go right to the dealloc
    >>> method (and init if I have one) and ensure I've managed that
    >>> property before I forget.
    >>
    >> Yes, but this is exactly the point.  If I have no property for an
    >> Outlet it's still retained.
    >
    > Hey Brian -
    >
    > Outlets for iPhone OS are established by calling
    > setValue:forKeyPath:. The behavior of setValue:forKeyPath: is that
    > if a setter exists, it is called. If a setter does not exist, the
    > instance variable is looked up and set directly, and if it is an
    > object, it is retained. This means that for IBOutlets, with no
    > setters, they're retained in iPhone OS. This is different from Mac
    > OS X. If you're writing code on both platforms, or are planning to,
    > you should always use properties on both platforms since it makes
    > the decision to retain outlets explicit and obvious.

    How come the documentation that mmalc quoted doesn't have this clear
    statement?

    >
    >
    > Jon Hess

    --
    Brian Stern
    <brians99...>
  • On Nov 18, 2008, at 12:43 AM, Brian Stern wrote:

    >
    > On Nov 18, 2008, at 12:34 AM, Jonathan Hess wrote:
    >
    >>
    >> The solution to a memory leak should never be an unbalanced release.
    >
    > What I did to fix this was to add all of the properties to all of
    > the outlets so they'd all be retained through those properties.
    > Then I added all the releases to all the deallocs to match those
    > retains.

    From the later messages in this thread, it looks you didn't insert an
    unbalanced retain after all. The retains and releases were balanced,
    but the code wasn't executing as expected because the setters weren't
    being used because the outlets had different names than the properties.

    If you do encounter a leak like this in the future, please head my
    advice. Inserting a unbalanced retain or release might fix a symptom,
    but is likely to come back up as a hard to debug problem in the future.

    Good Luck -
    Jon Hess

    >
    >
    > --
    > Brian Stern
    > <brians99...>
  • >>
    >> Hey Brian -
    >>
    >> Outlets for iPhone OS are established by calling
    >> setValue:forKeyPath:. The behavior of setValue:forKeyPath: is that
    >> if a setter exists, it is called. If a setter does not exist, the
    >> instance variable is looked up and set directly, and if it is an
    >> object, it is retained. This means that for IBOutlets, with no
    >> setters, they're retained in iPhone OS. This is different from Mac
    >> OS X. If you're writing code on both platforms, or are planning to,
    >> you should always use properties on both platforms since it makes
    >> the decision to retain outlets explicit and obvious.
    >
    >
    > How come the documentation that mmalc quoted doesn't have this clear
    > statement?

    which one did he quote, the one I suggested to you has it .. it's under
    Nib Object Retention. It's a page I have bookmarked because as I switch
    between iPhone and regular OSX I like to remind myself what it says.
    It's pasted below.

    iPhone OS - managed memory model

    Objects in the nib file are created with a retain count of 1 and then
    autoreleased. As it rebuilds the object hierarchy, however, UIKit
    reestablishes connections between the objects using the
    |setValue:forKey:| method, which uses the available setter method or
    retains the object by default if no setter method is available. If you
    define outlets for nib-file objects, you should also define a setter
    method for accessing that outlet. Setter methods for outlets should
    retain their values, and setter methods for outlets containing top-level
    objects must retain their values to prevent them from being deallocated.
    If you do not store the top-level objects in outlets, you must retain
    either the array returned by the |loadNibNamed:owner:options:| method or
    the objects inside the array to prevent those objects from being
    released prematurely.
  • On Nov 18, 2008, at 12:49 AM, Brian Stern wrote:

    >
    > On Nov 18, 2008, at 12:35 AM, Jonathan Hess wrote:
    >>
    >> Normally instance variables and properties share the same name,
    >
    > Normally in your code maybe, not mine.
    >
    >> so it doesn't matter to Interface Builder where the 'IBOutlet' text
    >> appears. If you're going to give your instance variables different
    >> names though, you need to put the IBOutlet qualifier on the
    >> property if you want it to be used.
    >
    > I guess I just had a perfect storm of issues that made it appear
    > that things were working differently from the way they were
    > working.  My properties, though present, were ignored. The fact that
    > it works differently from Mac OS makes it worse.

    Which difference are you referring to? It sounds like you're referring
    to the fact that if a setter doesn't exist the variable is retained by
    setValue:forKeyPath:. To avoid implementing setters, you're free to
    them out and let IB directly set you're iVars. If you do that, you'll
    just need to release them in dealloc. The best practices are there to
    help developers who are new to both platforms. If you feel that you
    have an adequate understanding of how the outlets are established,
    you're free to use a pattern that you prefer.

    Jon Hess

    >
    >
    > Thanks for the help guys.
    >
    > --
    > Brian Stern
    > <brians99...>
  • On Nov 18, 2008, at 12:49 AM, Brian Stern wrote:

    >
    > On Nov 18, 2008, at 12:35 AM, Jonathan Hess wrote:
    >
    >>>> Perhaps the new @property() syntax makes it easy to forget about
    >>>> object lifetimes because it does the set/get/change
    >>>> automagically. These days when I add any property I go right to
    >>>> the dealloc method (and init if I have one) and ensure I've
    >>>> managed that property before I forget.
    >>>
    >>> Yes, but this is exactly the point.  If I have no property for an
    >>> Outlet it's still retained.
    >>
    >> Hey Brian -
    >>
    >> Outlets for iPhone OS are established by calling
    >> setValue:forKeyPath:. The behavior of setValue:forKeyPath: is that
    >> if a setter exists, it is called. If a setter does not exist, the
    >> instance variable is looked up and set directly, and if it is an
    >> object, it is retained. This means that for IBOutlets, with no
    >> setters, they're retained in iPhone OS. This is different from Mac
    >> OS X. If you're writing code on both platforms, or are planning to,
    >> you should always use properties on both platforms since it makes
    >> the decision to retain outlets explicit and obvious.
    >
    > How come the documentation that mmalc quoted doesn't have this clear
    > statement?

    Hey Brian -

    Check out "Table 2-1". It states all of this explicitly.

    Jon Hess

    >
    >
    >
    >>
    >>
    >> Jon Hess
    >
    > --
    > Brian Stern
    > <brians99...>
  • On Nov 18, 2008, at 1:00 AM, Jonathan Hess wrote:

    >
    > On Nov 18, 2008, at 12:49 AM, Brian Stern wrote:
    >
    >>
    >> On Nov 18, 2008, at 12:35 AM, Jonathan Hess wrote:
    >>>
    >>> Normally instance variables and properties share the same name,
    >>
    >> Normally in your code maybe, not mine.
    >>
    >>> so it doesn't matter to Interface Builder where the 'IBOutlet'
    >>> text appears. If you're going to give your instance variables
    >>> different names though, you need to put the IBOutlet qualifier on
    >>> the property if you want it to be used.
    >>
    >> I guess I just had a perfect storm of issues that made it appear
    >> that things were working differently from the way they were
    >> working.  My properties, though present, were ignored. The fact
    >> that it works differently from Mac OS makes it worse.
    >
    > Which difference are you referring to? It sounds like you're
    > referring to the fact that if a setter doesn't exist the variable is
    > retained by setValue:forKeyPath:.

    Yes, that's the one.

    > To avoid implementing setters, you're free to them out and let IB
    > directly set you're iVars. If you do that, you'll just need to
    > release them in dealloc. The best practices are there to help
    > developers who are new to both platforms. If you feel that you have
    > an adequate understanding of how the outlets are established, you're
    > free to use a pattern that you prefer.

    I understand it better now.

    --
    Brian Stern
    <brians99...>
  • On Nov 18, 2008, at 12:59 AM, Roland King wrote:

    >
    >>>
    >>> Hey Brian -
    >>>
    >>> Outlets for iPhone OS are established by calling
    >>> setValue:forKeyPath:. The behavior of setValue:forKeyPath: is
    >>> that  if a setter exists, it is called. If a setter does not
    >>> exist, the  instance variable is looked up and set directly, and
    >>> if it is an  object, it is retained. This means that for
    >>> IBOutlets, with no  setters, they're retained in iPhone OS. This
    >>> is different from Mac  OS X. If you're writing code on both
    >>> platforms, or are planning to,  you should always use properties
    >>> on both platforms since it makes  the decision to retain outlets
    >>> explicit and obvious.
    >>
    >>
    >> How come the documentation that mmalc quoted doesn't have this
    >> clear  statement?
    >
    >
    > which one did he quote, the one I suggested to you has it .. it's
    > under Nib Object Retention. It's a page I have bookmarked because as
    > I switch between iPhone and regular OSX I like to remind myself what
    > it says. It's pasted below.

    Yes, that's it.  I've read it plenty of times.

    >
    >
    > iPhone OS - managed memory model
    >
    > Objects in the nib file are created with a retain count of 1 and
    > then autoreleased. As it rebuilds the object hierarchy, however,
    > UIKit reestablishes connections between the objects using the |
    > setValue:forKey:| method, which uses the available setter method or
    > retains the object by default if no setter method is available.

    I admit that I didn't internalize this statement because the behavior
    is different from the Mac.  I also didn't internalize this because it
    seems to contradict the standard Cocoa memory management rules.  My
    code doesn't retain the outlets so it shouldn't have to release them.

    > If you define outlets for nib-file objects, you should also define a
    > setter method for accessing that outlet.

    Why SHOULD?

    > Setter methods for outlets should

    Why SHOULD?

    > retain their values, and setter methods for outlets containing top-
    > level objects must retain their values to prevent them from being
    > deallocated. If you do not store the top-level objects in outlets,
    > you must retain either the array returned by the |
    > loadNibNamed:owner:options:| method or the objects inside the array
    > to prevent those objects from being released prematurely.

    In a nib loaded by UIViewController I have no access to the top level
    objects array so this isn't usually relevant.

    The shoulds in there confused me.  The fact that the behavior is
    different from the Mac confused me.  The fact that the behavior seems
    contrary to standard Cocoa memory management rules confused me.  I
    assure you that I'm not the only person confused by this and who
    doesn't understand this.
  • On Nov 18, 2008, at 1:14 AM, Brian Stern wrote:

    >
    > On Nov 18, 2008, at 12:59 AM, Roland King wrote:
    >
    >>
    >>>>
    >>>> Hey Brian -
    >>>>
    >>>> Outlets for iPhone OS are established by calling
    >>>> setValue:forKeyPath:. The behavior of setValue:forKeyPath: is
    >>>> that  if a setter exists, it is called. If a setter does not
    >>>> exist, the  instance variable is looked up and set directly, and
    >>>> if it is an  object, it is retained. This means that for
    >>>> IBOutlets, with no  setters, they're retained in iPhone OS. This
    >>>> is different from Mac  OS X. If you're writing code on both
    >>>> platforms, or are planning to,  you should always use properties
    >>>> on both platforms since it makes  the decision to retain outlets
    >>>> explicit and obvious.
    >>>
    >>>
    >>> How come the documentation that mmalc quoted doesn't have this
    >>> clear  statement?
    >>
    >>
    >> which one did he quote, the one I suggested to you has it .. it's
    >> under Nib Object Retention. It's a page I have bookmarked because
    >> as I switch between iPhone and regular OSX I like to remind myself
    >> what it says. It's pasted below.
    >
    > Yes, that's it.  I've read it plenty of times.
    >
    >
    >>
    >>
    >> iPhone OS - managed memory model
    >>
    >> Objects in the nib file are created with a retain count of 1 and
    >> then autoreleased. As it rebuilds the object hierarchy, however,
    >> UIKit reestablishes connections between the objects using the |
    >> setValue:forKey:| method, which uses the available setter method or
    >> retains the object by default if no setter method is available.
    >
    > I admit that I didn't internalize this statement because the
    > behavior is different from the Mac.  I also didn't internalize this
    > because it seems to contradict the standard Cocoa memory management
    > rules.  My code doesn't retain the outlets so it shouldn't have to
    > release them.
    >
    >> If you define outlets for nib-file objects, you should also define
    >> a setter method for accessing that outlet.
    >
    > Why SHOULD?

    So that it's obvious to the reader of the code what is retained, and
    what isn't. If you have setters then you can easily look at the .m
    file and verify that the retains and releases are all balanced without
    having to know anything else.

    >> Setter methods for outlets should
    >
    > Why SHOULD?

    You're free to have an outlet be non-retained, it's up to you. The
    same rules should apply to outlets that apply to other instance
    variables. You should retain your instance variables so they don't go
    away when you don't expect them to. You just have to watch out for
    creating cycles. If you do create a cycle, you can either break it
    explicitly, or you can use some non-retained instance variables.

    >
    >
    >> retain their values, and setter methods for outlets containing top-
    >> level objects must retain their values to prevent them from being
    >> deallocated. If you do not store the top-level objects in outlets,
    >> you must retain either the array returned by the |
    >> loadNibNamed:owner:options:| method or the objects inside the array
    >> to prevent those objects from being released prematurely.
    >
    > In a nib loaded by UIViewController I have no access to the top
    > level objects array so this isn't usually relevant.
    >
    > The shoulds in there confused me.  The fact that the behavior is
    > different from the Mac confused me.  The fact that the behavior
    > seems contrary to standard Cocoa memory management rules confused me.

    Which parts do you feel are contrary? I'm guessing it's that outlets
    with no setters are retained. If that's the case, you might consider
    thinking of it this way: Interface Builder for the iPhone uses key
    value coding. That's really the truth of the matter and accurately
    describes everything that is going on. That outlets without a setter
    are retained is a side effect of using key value coding. Additionally
    having the outlet retain by default, and making that be the
    recommendation when you use properties or setters comes into balance
    with the fact you don't have to send a release massage to each top
    level nib object after loading a NIB on the iPhone. With that, the
    memory management rules for NIB loading on the iPhone actually pretty
    concise:

    1. Outlets are set with key value coding - implies outlets with no
    setters are retained.
    2. If you retain an outlet, you must release it.
    3. If you want something to stay alive after the call to
    loadNibNamed: you need to retain it in some way.

    There really isn't anything in that list that is out of line with
    Cocoa memory management patterns.

    Also, just incase you aren't familiar with it, here's a link to the
    key value coding programming guide: http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/

    Good Luck -
    Jon Hess

    > I assure you that I'm not the only person confused by this and who
    > doesn't understand this.
  • On Nov 18, 2008, at 2:12 AM, Jonathan Hess wrote:

    > Which parts do you feel are contrary? I'm guessing it's that outlets
    > with no setters are retained.

    Yes, that's the root of the whole issue.  The fact is that outlets
    without setters that are retained aren't released by the code that
    retained them.  The responsibility for releasing them is implicitly
    passed on to some other code.  I misunderstood this after reading that
    paragraph a number of times because it is simply contrary to my
    understanding of Cocoa memory management.  I think it is contrary to
    the Cocoa memory management rules that the code that retains these
    objects isn't releasing them.

    Now that I know that, there are still problems.  The outlets can be
    released in more than one place.  As mmalc mentioned, the view
    controller's view may be unloaded in response to a memory warning.
    However, the view won't be unloaded if the view controller is the
    frontmost view controller.  There's no simple way for a view
    controller subclass to know if it's the frontmost view controller or
    therefore if its view will be unloaded.  There is no viewDidUnload
    callback that would be the right place to release the outlets in this
    case.  The code that mmalc showed is not correct because it doesn't
    take into account the fact that the frontmost view controller won't
    unload its view.

    In effect it is the UIViewController base class that is retaining the
    outlets, or causing them to be retained, when the nib is loaded.  But
    it abdicates responsibility for them.  The UIViewController base class
    is also the class that is releasing its view without any notification
    to the derived class that it should also release the outlets.

    I haven't decided how I'm going to fix all this.  Either I'll add
    assign properties so the outlets are not retained or I'll release them
    all in viewDidLoad.

    Most nib-loading on iPhone OS is done by UIViewController and I
    suppose most of my complaints above are with the UIViewController
    implementation.  In my code I would hardly ever have a reason to want
    to retain an outlet.  Having outlets be retained by default gives my
    code no benefit, and causes some complications.

    --
    Brian Stern
    <brians99...>
  • On Nov 17, 2008, at 9:33 PM, Jeff Laing wrote:

    > How about:
    > http://developer.apple.com/samplecode/CacheInfo-MacOSX/listing1.html
    > (for example) which has the IBOutlet tag on the instance variables
    > rather than the properties; I'll bet its different because properties
    > and instance vars have the same name, isn't it?
    >
    No, it's because it hasn't been updated.

    > That example declares dozens of IBOutlet's, whose properties are
    > (nonatomic,retain) and doesn't release any of them in its dealloc.
    >
    That's a bug (filed).

    mmalc
previous month november 2008 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today
MindNode
MindNode offered a free license !