initWithFrame not being called on my NSImageView subclass

  • I've written a subclass of NSImageView, and my intent was to set some
    sane default values for some member vars in my initWithFrame:
    ( NSRect ) method.

    However... initWithFrame simply isn't being called. I know the
    instance is being instantiated ( it's the main view for a document
    based app ) and messages are going to/from the instance. All my
    bindings work, for example. The trouble is, initWithFrame is never
    called and as such, my member vars are all set to zero, and thus some
    things are wonky.

    In principle, I could probably use awakeFromNib and the like, but I'm
    concerned that initWithFrame isn't being called.

    Anybody know why it wouldn't be called? It doesn't appear to be
    misspelled.

    For reference, this is a document based app. 10.5.2, using the 10.5
    SDK. No GC.

    <shamyl...>
      "Our response to being bored and rich is not to discard
      possessions and live more simply, but to buy more stuff
      to reduce the space in which we might contemplate
      our shame."
  • On Thu, Feb 21, 2008 at 1:36 PM, Shamyl Zakariya <shamyl...> wrote:
    > Anybody know why it wouldn't be called? It doesn't appear to be
    > misspelled.

    Re-read the documentation here:
    http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaViewsGuide/S
    ubclassingNSView/chapter_6_section_2.html


    Short version: subclasses of views that you've put in your nib have
    already been instantiated when they were freeze-dried into the nib.
    It would be incorrect to call -initWithFrame: again.  That's why you
    have -awakeFromNib.

    --Kyle Sluder
  • If the view's being loaded from a nib it's archived, so you need -
    initWithCoder:

    Mike.

    On 21 Feb 2008, at 18:36, Shamyl Zakariya wrote:

    > I've written a subclass of NSImageView, and my intent was to set
    > some sane default values for some member vars in my initWithFrame:
    > ( NSRect ) method.
    >
    > However... initWithFrame simply isn't being called. I know the
    > instance is being instantiated ( it's the main view for a document
    > based app ) and messages are going to/from the instance. All my
    > bindings work, for example. The trouble is, initWithFrame is never
    > called and as such, my member vars are all set to zero, and thus
    > some things are wonky.
    >
    > In principle, I could probably use awakeFromNib and the like, but
    > I'm concerned that initWithFrame isn't being called.
    >
    > Anybody know why it wouldn't be called? It doesn't appear to be
    > misspelled.
    >
    > For reference, this is a document based app. 10.5.2, using the 10.5
    > SDK. No GC.
    >
    > <shamyl...>
    > "Our response to being bored and rich is not to discard
    > possessions and live more simply, but to buy more stuff
    > to reduce the space in which we might contemplate
    > our shame."
  • On Thu, Feb 21, 2008 at 2:06 PM, Mike Abdullah
    <cocoadev...> wrote:
    > If the view's being loaded from a nib it's archived, so you need -
    > initWithCoder:

    I'm not sure -initWithCoder: is guaranteed to be called, and is
    certainly not the "proper" place to be performing object
    initialization after awaking from a nib.  The official recommendation
    is to either create an IB plugin so that your version of
    -initWithFrame: is called at design time, or perform subclass-specific
    initialization in -awakeFromNib.

    http://lists.apple.com/archives/cocoa-dev/2002/Jul/msg01647.html

    --Kyle Sluder
  • That makes sense, thank you.

    <shamyl...>
        "Such a theory has to be bizarre and elaborate, as well as being
    stupid"
            -- Jim Loy, regarding a hollow earth

    On Feb 21, 2008, at 2:00 PM, Kyle Sluder wrote:

    > On Thu, Feb 21, 2008 at 1:36 PM, Shamyl Zakariya
    > <shamyl...> wrote:
    >> Anybody know why it wouldn't be called? It doesn't appear to be
    >> misspelled.
    >
    > Re-read the documentation here:
    > http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaViewsGuide/S
    ubclassingNSView/chapter_6_section_2.html

    >
    > Short version: subclasses of views that you've put in your nib have
    > already been instantiated when they were freeze-dried into the nib.
    > It would be incorrect to call -initWithFrame: again.  That's why you
    > have -awakeFromNib.
    >
    > --Kyle Sluder
  • Wonderful! Now I have sane defaults and my controls bound to them have
    the correct values.

    Thanks for your help.

    <shamyl...>
        "finite=alright"
            --David Byrne

    On Feb 21, 2008, at 2:06 PM, Mike Abdullah wrote:

    > If the view's being loaded from a nib it's archived, so you need -
    > initWithCoder:
    >
    > Mike.
    >
    > On 21 Feb 2008, at 18:36, Shamyl Zakariya wrote:
    >
    >> I've written a subclass of NSImageView, and my intent was to set
    >> some sane default values for some member vars in my initWithFrame:
    >> ( NSRect ) method.
    >>
    >> However... initWithFrame simply isn't being called. I know the
    >> instance is being instantiated ( it's the main view for a document
    >> based app ) and messages are going to/from the instance. All my
    >> bindings work, for example. The trouble is, initWithFrame is never
    >> called and as such, my member vars are all set to zero, and thus
    >> some things are wonky.
    >>
    >> In principle, I could probably use awakeFromNib and the like, but
    >> I'm concerned that initWithFrame isn't being called.
    >>
    >> Anybody know why it wouldn't be called? It doesn't appear to be
    >> misspelled.
    >>
    >> For reference, this is a document based app. 10.5.2, using the 10.5
    >> SDK. No GC.
    >>
    >> <shamyl...>
    >> "Our response to being bored and rich is not to discard
    >> possessions and live more simply, but to buy more stuff
    >> to reduce the space in which we might contemplate
    >> our shame."
    >
  • OK, sounds like I'm not out of the woods.

    Here's the trouble: I have some controls ( in my toolbar ) controlling
    a couple properties of the image view subclass. Specifically, a zoom
    factor and a tiling mode ( this is just a quick-dirty app for viewing
    compressed DDS textures. I've already written a quicklook plugin and
    an NSCustomBitmapImageRep so the plumbing's all there ).

    When I assign a default tiling mode and zoom factor in awakeFromNib,
    for some reason it doesn't "propagate" to the bindings.

    NSLogging the order of events, I see something like this:

    1) new document is opened from a DDS file:
    2) TilingImageView is asked for a scaling factor. _scale is zero so it
    returns zero
    3) awakeFromNib is called. I call setScale: 1
    4) Nothing. My slider's still showing zero.

    Now, my slider does work: Dragging it changes the scaling factor. But
    for some reason calling [self setScale: 1] in awakeFromNib doesn't
    notify the slider in my toolbar.

    This is why I'm trying to find a way to make certain _scale = 1 before
    bindings queries my image view instance.

    <shamyl...>
        "In the same trial, only 16 percent of those who received placebo
          sandwiches reported experiencing high levels of deliciousness."
            --The Onion

    On Feb 21, 2008, at 2:15 PM, Kyle Sluder wrote:

    > On Thu, Feb 21, 2008 at 2:06 PM, Mike Abdullah
    > <cocoadev...> wrote:
    >> If the view's being loaded from a nib it's archived, so you need -
    >> initWithCoder:
    >
    > I'm not sure -initWithCoder: is guaranteed to be called, and is
    > certainly not the "proper" place to be performing object
    > initialization after awaking from a nib.  The official recommendation
    > is to either create an IB plugin so that your version of
    > -initWithFrame: is called at design time, or perform subclass-specific
    > initialization in -awakeFromNib.
    >
    > http://lists.apple.com/archives/cocoa-dev/2002/Jul/msg01647.html
    >
    > --Kyle Sluder
  • Well, to finish this off, I just made some calls to initialize from
    windowControllerDidLoadNib and averything's peachy, and no dependancy
    on initWithCoder.

    Shamyl Zakariya
    - The fantabulous contrapulation of professor Horatio Huffnagel

    On Feb 21, 2008, at 2:30 PM, Shamyl Zakariya wrote:

    > OK, sounds like I'm not out of the woods.
    >
    > Here's the trouble: I have some controls ( in my toolbar )
    > controlling a couple properties of the image view subclass.
    > Specifically, a zoom factor and a tiling mode ( this is just a quick-
    > dirty app for viewing compressed DDS textures. I've already written
    > a quicklook plugin and an NSCustomBitmapImageRep so the plumbing's
    > all there ).
    >
    > When I assign a default tiling mode and zoom factor in awakeFromNib,
    > for some reason it doesn't "propagate" to the bindings.
    >
    > NSLogging the order of events, I see something like this:
    >
    > 1) new document is opened from a DDS file:
    > 2) TilingImageView is asked for a scaling factor. _scale is zero so
    > it returns zero
    > 3) awakeFromNib is called. I call setScale: 1
    > 4) Nothing. My slider's still showing zero.
    >
    > Now, my slider does work: Dragging it changes the scaling factor.
    > But for some reason calling [self setScale: 1] in awakeFromNib
    > doesn't notify the slider in my toolbar.
    >
    > This is why I'm trying to find a way to make certain _scale = 1
    > before bindings queries my image view instance.
    >
    > <shamyl...>
    > "In the same trial, only 16 percent of those who received placebo
    > sandwiches reported experiencing high levels of deliciousness."
    > --The Onion
    >
    >
    > On Feb 21, 2008, at 2:15 PM, Kyle Sluder wrote:
    >
    >> On Thu, Feb 21, 2008 at 2:06 PM, Mike Abdullah
    >> <cocoadev...> wrote:
    >>> If the view's being loaded from a nib it's archived, so you need -
    >>> initWithCoder:
    >>
    >> I'm not sure -initWithCoder: is guaranteed to be called, and is
    >> certainly not the "proper" place to be performing object
    >> initialization after awaking from a nib.  The official recommendation
    >> is to either create an IB plugin so that your version of
    >> -initWithFrame: is called at design time, or perform subclass-
    >> specific
    >> initialization in -awakeFromNib.
    >>
    >> http://lists.apple.com/archives/cocoa-dev/2002/Jul/msg01647.html
    >>
    >> --Kyle Sluder

  • > I'm not sure -initWithCoder: is guaranteed to be called, and is
    > certainly not the "proper" place to be performing object
    > initialization after awaking from a nib.

    What's guaranteed is that all init methods on a class will funnel into
    one of the designated init methods.  A subclasser should always
    override all designated initializers of the superclass (if he needs to
    do work at initialization time).  Then you're guaranteed to have your
    setup performed no matter how the object is created.

    For NSView, -initWithFrame: and -initWithCoder: are the designated
    initializers.

    -awakeFromNib is good if the work you're doing involves other objects
    from a nib.  In particular, there's a subtlety with decoding from an
    archive: suppose two objects refer to each other and encode each other
    (with encodeObject:forKey:) in a nib.  Well, one of them has to finish
    initializing before the other.  The upshot is that when you call
    -decodeObject:forKey: in -initWithCoder:, you'll get back an object,
    but it may not have finished its initialization yet.  It's fine to
    send messages defined at the NSObject level (like -retain) to it, but
    not to treat it as a full fledged object of whatever class you know it
    to be.

    In -awakeFromNib you're guaranteed that all objects in the nib have
    been through initialization had have their outlets hooked up.

    -Ken
    Cocoa Frameworks

    On Thu, Feb 21, 2008 at 11:15 AM, Kyle Sluder
    <kyle.sluder+<cocoa-dev...> wrote:
    > On Thu, Feb 21, 2008 at 2:06 PM, Mike Abdullah
    > <cocoadev...> wrote:
    >> If the view's being loaded from a nib it's archived, so you need -
    >> initWithCoder:
    >
    > I'm not sure -initWithCoder: is guaranteed to be called, and is
    > certainly not the "proper" place to be performing object
    > initialization after awaking from a nib.  The official recommendation
    > is to either create an IB plugin so that your version of
    > -initWithFrame: is called at design time, or perform subclass-specific
    > initialization in -awakeFromNib.
    >
    > http://lists.apple.com/archives/cocoa-dev/2002/Jul/msg01647.html
    >
    > --Kyle Sluder
    >
  • On Thu, Feb 21, 2008 at 11:30 AM, Shamyl Zakariya <shamyl...> wrote:
    > OK, sounds like I'm not out of the woods.
    >
    > Here's the trouble: I have some controls ( in my toolbar ) controlling
    > a couple properties of the image view subclass. Specifically, a zoom
    > factor and a tiling mode ( this is just a quick-dirty app for viewing
    > compressed DDS textures. I've already written a quicklook plugin and
    > an NSCustomBitmapImageRep so the plumbing's all there ).
    >
    > When I assign a default tiling mode and zoom factor in awakeFromNib,
    > for some reason it doesn't "propagate" to the bindings.
    >
    > NSLogging the order of events, I see something like this:
    >
    > 1) new document is opened from a DDS file:
    > 2) TilingImageView is asked for a scaling factor. _scale is zero so it
    > returns zero
    > 3) awakeFromNib is called. I call setScale: 1

    Are you calling setScale: on the model object, or on the view?
    Calling a setter on a bound view object does not propagate the change
    to the model.

    It's basically exactly like pre-bindings models like delegates or
    target-action.  The model and the view are not completely aliased to
    each other, but each updates the other under certain circumstances.
    Typically the view updates the model in response to user actions like
    a mouse click, not programmatic actions like calling a setter.

    -Ken

    > 4) Nothing. My slider's still showing zero.
    >
    > Now, my slider does work: Dragging it changes the scaling factor. But
    > for some reason calling [self setScale: 1] in awakeFromNib doesn't
    > notify the slider in my toolbar.
    >
    > This is why I'm trying to find a way to make certain _scale = 1 before
    > bindings queries my image view instance.
    >
    > <shamyl...>
    > "In the same trial, only 16 percent of those who received placebo
    > sandwiches reported experiencing high levels of deliciousness."
    > --The Onion
    >
    >
    >
    >
    > On Feb 21, 2008, at 2:15 PM, Kyle Sluder wrote:
    >
    >> On Thu, Feb 21, 2008 at 2:06 PM, Mike Abdullah
    >> <cocoadev...> wrote:
    >>> If the view's being loaded from a nib it's archived, so you need -
    >>> initWithCoder:
    >>
    >> I'm not sure -initWithCoder: is guaranteed to be called, and is
    >> certainly not the "proper" place to be performing object
    >> initialization after awaking from a nib.  The official recommendation
    >> is to either create an IB plugin so that your version of
    >> -initWithFrame: is called at design time, or perform subclass-specific
    >> initialization in -awakeFromNib.
    >>
    >> http://lists.apple.com/archives/cocoa-dev/2002/Jul/msg01647.html
    >>
    >> --Kyle Sluder

    >
  • On Thu, Feb 21, 2008 at 2:41 PM, Ken Ferry <kenferry...> wrote:
    > What's guaranteed is that all init methods on a class will funnel into
    > one of the designated init methods.  A subclasser should always
    > override all designated initializers of the superclass (if he needs to
    > do work at initialization time).  Then you're guaranteed to have your
    > setup performed no matter how the object is created.

    What I'm saying is that I'm not sure this is guaranteed to be true for
    unarchiving.  Since (with rare exception) any override of a designated
    initializer is supposed to call super's implementation, it would be
    very easy to introduce improper behavior by calling -[NSView
    initWithFrame:] at design time, archiving the object graph into the
    nib, and then calling -[MyView initWithFrame:], which then invokes
    -[NSView initWithFrame:], when unarchiving the view from the nib.

    I think the Apple docs are pretty clear that there is no guarantee
    whatsoever that any initializer will be called on your objects when
    unarchiving from a nib.  The nib unarchiving mechanism doesn't really
    care about your setters, getters, and initializers.  It restores
    whatever state it knew about when it archived the object, trusting you
    to implement -awakeFromNib if you need subclass-specific processing.

    --Kyle Sluder
  • On Thu, Feb 21, 2008 at 1:46 PM, Kyle Sluder
    <kyle.sluder+<cocoa-dev...> wrote:
    > On Thu, Feb 21, 2008 at 2:41 PM, Ken Ferry <kenferry...> wrote:
    >> What's guaranteed is that all init methods on a class will funnel into
    >> one of the designated init methods.  A subclasser should always
    >> override all designated initializers of the superclass (if he needs to
    >> do work at initialization time).  Then you're guaranteed to have your
    >> setup performed no matter how the object is created.
    >
    > What I'm saying is that I'm not sure this is guaranteed to be true for
    > unarchiving.  Since (with rare exception) any override of a designated
    > initializer is supposed to call super's implementation, it would be
    > very easy to introduce improper behavior by calling -[NSView
    > initWithFrame:] at design time, archiving the object graph into the
    > nib, and then calling -[MyView initWithFrame:], which then invokes
    > -[NSView initWithFrame:], when unarchiving the view from the nib.
    >
    > I think the Apple docs are pretty clear that there is no guarantee
    > whatsoever that any initializer will be called on your objects when
    > unarchiving from a nib.  The nib unarchiving mechanism doesn't really
    > care about your setters, getters, and initializers.  It restores
    > whatever state it knew about when it archived the object, trusting you
    > to implement -awakeFromNib if you need subclass-specific processing.

    Hm, sorry if the docs confused you.. if you can point at the docs that
    made you think this, it'd be great to have a bug.

    All objects _do_ go through some init method, including those in a
    nib, and every init method of a class is intended to call through to a
    designated initializer.  You can count on this.  -awakeFromNib is
    great for setup that really does have to do with a nib, but pure
    initial object initialization is better done in an init method.
    Otherwise, you risk that setup not getting done if your object is
    created in a way that doesn't involve a nib.  For example,
    NSCollectionView and NSToolbar with both sometimes try to 'copy' view
    hierarchies by encoding and decoding to a keyed archive.  (That kind
    of copying is really hard to get right, by the way.)

    As Ondra described, there is complexity in exactly which init method
    is used for what object that you see in IB, but if you override all of
    the designated initializers then your code won't care which init
    method actually gets called.  It might be any of -init,
    -initWithCoder:, or -initWithFrame:, depending.  IB will also show a
    few objects that are actually external to the nib, like the nib file's
    owner and the shared NSApplication object.  These few objects already
    existed and were initialized before the nib was instantiated, so they
    won't get an init method when the nib is coming up.

    Ken Ferry
    Cocoa Frameworks
  • On Feb 21, 2008, at 14:06, Ken Ferry wrote:

    > Hm, sorry if the docs confused you.. if you can point at the docs that
    > made you think this, it'd be great to have a bug.

    There's:

    http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaViewsGuide/S
    ubclassingNSView/chapter_6_section_2.html#/

    /apple_ref/doc/uid/TP40002978-CH7-DontLinkElementID_12

    It doesn't actually say that unarchived nib views *don't* go through
    initWithCoder, but it doesn't promise that either.

    Incidentally, that document was written pre-Leopard, and in IB 3
    there's a third case. If you have a IB plugin that creates the view,
    then the subclass initWithFrame *is* going to get called (from within
    IB). At least I think so.
previous month february 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    
Go to today
MindNode
MindNode offered a free license !