Overriding -copyWithZone: the right way

  • Hello all!

    I have a subclass of NSCell (for a TableView) that is supposed to
    display an image and an NSPopUpButtonCell. Everything works fine so
    far, but I obviously need to override -copyWithZone:. Here's what I
    came up with:

    - (id)copyWithZone:(NSZone *)zone {
    PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    initImageCell:nil];
    return copy;
    }

    This does not crash, but it looks so suspiciously memory-leaking...
    (the alloc/init is not paired with a release on my side). When trying
    to follow the (few) suggestions the docs give me, I tried this (but it
    did not work, the app crashed as soon as the TableView wanted to
    redraw):

    - (id)copyWithZone:(NSZone *)zone
    {
    PCShoppingCartCell *copy = [super copyWithZone:zone];
    [ copy _initSubCells]; // This inits and sets up the NSPopUpButtonCell
    return copy;
    }

    Can anybody give me advice on how I do this the right way?

    Kind regards,
    Michael
  • On 6 Nov 2004, at 03:16, Michael Becker wrote:

    > I have a subclass of NSCell (for a TableView) that is supposed to
    > display an image and an NSPopUpButtonCell. Everything works fine so
    > far, but I obviously need to override -copyWithZone:. Here's what I
    > came up with:
    >
    > - (id)copyWithZone:(NSZone *)zone {
    > PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    > initImageCell:nil];
    > return copy;
    > }
    >
    > This does not crash, but it looks so suspiciously memory-leaking...
    > (the alloc/init is not paired with a release on my side).

    As far as I'm aware, returning a copy with retain count 1 is the right
    thing to do. As you probably know, you need to pair alloc/release, as
    well as copy/release (in other general code). Therefore a copied object
    must be returned with a retain count of 1, or it'd be over-released.

    > When trying to follow the (few) suggestions the docs give me, I tried
    > this (but it did not work, the app crashed as soon as the TableView
    > wanted to redraw):
    >
    > - (id)copyWithZone:(NSZone *)zone
    > {
    > PCShoppingCartCell *copy = [super copyWithZone:zone];
    > [ copy _initSubCells]; // This inits and sets up the NSPopUpButtonCell
    > return copy;
    > }

    What you're doing there is calling copyWithZone: on the superclass,
    NSCell. This returns an NSCell (which wouldn't implement your own
    _initSubCells method), not a PCShoppingCartCell.

    Jonathon Mah
    <me...>
  • At 17:46 Uhr +0100 05.11.2004, Michael Becker wrote:
    > - (id)copyWithZone:(NSZone *)zone {
    > PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    > initImageCell:nil];
    > return copy;
    > }
    >
    > This does not crash, but it looks so suspiciously memory-leaking...
    > (the alloc/init is not paired with a release on my side). When
    > trying to follow the (few) suggestions the docs give me, I tried
    > this (but it did not work, the app crashed as soon as the TableView
    > wanted to redraw):

      That's just fine. It doesn't leak, because methods with "copy" in
    their name, by definition, return retained objects. So, whoever calls
    this method knows they're responsible for releasing the object they
    get.

      I'm not sure though whether you shouldn't be calling [super
    copyWithZone: zone] instead of allocating a new object, and then just
    copy over those instance variables your subclass adds to the ones of
    the superclass.
    --
    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
            "The Witnesses of TeachText are everywhere..."
                        http://www.zathras.de
  • Is there an Apple document that tells us how to do it exactly?

    I know we must return an object identical to "self" ... but do we
    invoke super copyWithZone? etc. etc.

    On Fri, 5 Nov 2004 19:31:36 +0100, M. Uli Kusterer
    <witness.of.teachtext...> wrote:
    > At 17:46 Uhr +0100 05.11.2004, Michael Becker wrote:
    >
    >
    >> - (id)copyWithZone:(NSZone *)zone {
    >> PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    >> initImageCell:nil];
    >> return copy;
    >> }
    >>
    >> This does not crash, but it looks so suspiciously memory-leaking...
    >> (the alloc/init is not paired with a release on my side). When
    >> trying to follow the (few) suggestions the docs give me, I tried
    >> this (but it did not work, the app crashed as soon as the TableView
    >> wanted to redraw):
    >
    > That's just fine. It doesn't leak, because methods with "copy" in
    > their name, by definition, return retained objects. So, whoever calls
    > this method knows they're responsible for releasing the object they
    > get.
    >
    > I'm not sure though whether you shouldn't be calling [super
    > copyWithZone: zone] instead of allocating a new object, and then just
    > copy over those instance variables your subclass adds to the ones of
    > the superclass.
    > --
    > Cheers,
    > M. Uli Kusterer
    > ------------------------------------------------------------
    > "The Witnesses of TeachText are everywhere..."
    > http://www.zathras.de
    >
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<jolivierld...>
    >
    > This email sent to <jolivierld...>
    >

    --
    --Olivier
  • On Nov 5, 2004, at 1:52 PM, Jean-Olivier Lanctôt wrote:

    > Is there an Apple document that tells us how to do it exactly?

    I was just looking into this yesterday.  Check out the NSCopying
    protocol docs.

    <http://developer.apple.com/documentation/Cocoa/Reference/Foundation/
    ObjC_classic/Protocols/NSCopying.html
    >

    DocoaBrowser also rocks for this:
    <http://www.iwascoding.com/DocoaBrowser/>

    > On Fri, 5 Nov 2004 19:31:36 +0100, M. Uli Kusterer
    > <witness.of.teachtext...> wrote:
    >> At 17:46 Uhr +0100 05.11.2004, Michael Becker wrote:
    >>
    >>
    >>> - (id)copyWithZone:(NSZone *)zone {
    >>> PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    >>> initImageCell:nil];
    >>> return copy;
    >>> }

    I implemented by copyWithZone: method using allocWithZone:, just to
    preserve the use of the zone argument.  I don't know if zones are used
    much any more, so maybe it's doesn't matter and a plain alloc: would
    suffice.

    - Bill
  • On Nov 5, 2004, at 12:52 PM, Jean-Olivier Lanctôt wrote:

    > Is there an Apple document that tells us how to do it exactly?
    >
    > I know we must return an object identical to "self" ... but do we
    > invoke super copyWithZone? etc. etc.
    >
    If the superclass supports NSCopying, you should use [super
    copyWithZone:zone].  If it does not, you are implementing the
    base-level copyWithZone; a super call is impossible.  In that case, you
    use alloc and init as normal, using your setters to set all the current
    object's instance variables on the new one.

    If the superclass supports copyWithZone and you therefore use [super
    copyWithZone:zone], keep in mind that your instance variables will be
    'lightly' (not sure the proper word) copied - they point to the same
    memory addresses but are NOT retained.  You therefore want to manually
    set all of your subclass's instasnce variables, like so:

    //Copy
    - (id)copyWithZone:(NSZone *)zone
    {
    MyClass *newCell = [super copyWithZone:zone];

    /* Font is a retained NSFont* */
    [newCell setFont:font];

    /* subString is a retained NSString* */
    [newCell setSubString:subString];
    return(newCell);
    }

    >
    > On Fri, 5 Nov 2004 19:31:36 +0100, M. Uli Kusterer
    > <witness.of.teachtext...> wrote:
    >> At 17:46 Uhr +0100 05.11.2004, Michael Becker wrote:
    >>
    >>
    >>> - (id)copyWithZone:(NSZone *)zone {
    >>> PCShoppingCartCell *copy = [[ PCShoppingCartCell alloc]
    >>> initImageCell:nil];
    >>> return copy;
    >>> }
    >>>
    >>> This does not crash, but it looks so suspiciously memory-leaking...
    >>> (the alloc/init is not paired with a release on my side). When
    >>> trying to follow the (few) suggestions the docs give me, I tried
    >>> this (but it did not work, the app crashed as soon as the TableView
    >>> wanted to redraw):
    >>
    >> That's just fine. It doesn't leak, because methods with "copy" in
    >> their name, by definition, return retained objects. So, whoever calls
    >> this method knows they're responsible for releasing the object they
    >> get.
    >>
    >> I'm not sure though whether you shouldn't be calling [super
    >> copyWithZone: zone] instead of allocating a new object, and then just
    >> copy over those instance variables your subclass adds to the ones of
    >> the superclass.
    >> --
    >> Cheers,
    >> M. Uli Kusterer
    >> ------------------------------------------------------------
    >> "The Witnesses of TeachText are everywhere..."
    >> http://www.zathras.de
    >>
    >>
    >> _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/
    >> <jolivierld...>
    >>
    >> This email sent to <jolivierld...>
    >>
    >
    >
    > --
    > --Olivier
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<evan.s...>
    >
    > This email sent to <evan.s...>
    >
  • At 13:52 Uhr -0500 05.11.2004, Jean-Olivier Lanctôt wrote:
    > Is there an Apple document that tells us how to do it exactly?
    >
    > I know we must return an object identical to "self" ... but do we
    > invoke super copyWithZone? etc. etc.

    Well, googling a little, the best docs are probably in:

    http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Tasks/
    ImplementCopy.html


    and then there's a little more in:

    http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_cl
    assic/Classes/NSObject.html#copy


    <<
      (id)copy
    Convenience method for classes that adopt the
    NSCopying protocol. This method returns the
    object returned by the NSCopying protocol method
    copyWithZone: where the zone is nil. An exception
    is raised if there is no implementation for
    copyWithZone:.

    NSObject does not itself support the NSCopying
    protocol. Subclasses must support the protocol
    and implement the copyWithZone: method. A
    subclass version of the copyWithZone: method
    should send the message to super first, to
    incorporate its implementation, unless the
    subclass descends directly from NSObject.
    >>

    More info in

    http://developer.apple.com/documentation/Cocoa/Reference/Foundation/ObjC_cl
    assic/Protocols/NSCopying.html#//apple_ref/doc/uid/20000053/BCIJFCDH


    <<
    - (id)copyWithZone:(NSZone *)zone
    Returns a new instance that's a copy of the
    receiver. Memory for the new instance is
    allocated from zone, which may be nil. If zone is
    nil, the new instance is allocated from the
    default zone, which is returned from the function
    NSDefaultMallocZone. The returned object is
    implicitly retained by the sender, who is
    responsible for releasing it. The copy returned
    is immutable if the consideration "immutable vs.
    mutable" applies to the receiving object;
    otherwise the exact nature of the copy is
    determined by the class.
    >>
    --
    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
            "The Witnesses of TeachText are everywhere..."
                        http://www.zathras.de
  • At 15:50 Uhr -0600 05.11.2004, Evan Schoenberg wrote:
    > If the superclass supports copyWithZone and you therefore use [super
    > copyWithZone:zone], keep in mind that your instance variables will
    > be 'lightly' (not sure the proper word) copied - they point to the
    > same memory addresses but are NOT retained.

      "Shallow copy" is what you're fishing for.

    > You therefore want to manually set all of your subclass's instasnce
    > variables, like so:
    >
    > //Copy
    > - (id)copyWithZone:(NSZone *)zone
    > {
    > MyClass *newCell = [super copyWithZone:zone];
    >
    > /* Font is a retained NSFont* */
    > [newCell setFont:font];
    >
    > /* subString is a retained NSString* */
    > [newCell setSubString:subString];
    > return(newCell);
    > }

    No! If your setFont: looks like the typical one:

    -(void)    setFont: (NSFont*)f
    {
    if( font != f )
    {
      [font release];
      font = [f retain];
    }
    }

    This will simply do nothing, and thus not retain the instance
    variable. Or if you're using the other variant:

    -(void)    setFont: (NSFont*)f
    {
    [font autorelease];
    font = [f retain];
    }

    This will release an object that was never retained by you, thus
    effectively also failing to do the additional "retain" needed to give
    your copy ownership of the NSFont. Apple recommends to do:

    -(id) copyWithZone: (NSZone*)zone
    {
    MyClass *newCell = [super copyWithZone: zone];

    newCell->font = nil;
    [newCell setFont: font];

    newCell->subString = nil;
    [newCell setSubString: subString];

    return newCell;
    }

    --
    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
            "The Witnesses of TeachText are everywhere..."
                        http://www.zathras.de
  • Well I just learned a new thing...

    anyway, I have this very WEIRD crash in my app (which is, BTW, the
    ONLY bug left until I can release 1.0) that I just can't squash.
    *Maybe* it has to do with my wrong manner of overriding copyWithZone??
    What do you guys think.. I have something like 5 custom classes
    implementing it and I don't do it the right way... so could that be
    the reason for weird crashes? I'm not on my work comp. right now so I
    can't check.

    On Fri, 5 Nov 2004 23:24:40 +0100, M. Uli Kusterer
    <witness.of.teachtext...> wrote:
    > At 15:50 Uhr -0600 05.11.2004, Evan Schoenberg wrote:
    >> If the superclass supports copyWithZone and you therefore use [super
    >> copyWithZone:zone], keep in mind that your instance variables will
    >> be 'lightly' (not sure the proper word) copied - they point to the
    >> same memory addresses but are NOT retained.
    >
    > "Shallow copy" is what you're fishing for.
    >
    >
    >
    >> You therefore want to manually set all of your subclass's instasnce
    >> variables, like so:
    >>
    >> //Copy
    >> - (id)copyWithZone:(NSZone *)zone
    >> {
    >> MyClass *newCell = [super copyWithZone:zone];
    >>
    >> /* Font is a retained NSFont* */
    >> [newCell setFont:font];
    >>
    >> /* subString is a retained NSString* */
    >> [newCell setSubString:subString];
    >> return(newCell);
    >> }
    >
    > No! If your setFont: looks like the typical one:
    >
    > -(void) setFont: (NSFont*)f
    > {
    > if( font != f )
    > {
    > [font release];
    > font = [f retain];
    > }
    > }
    >
    > This will simply do nothing, and thus not retain the instance
    > variable. Or if you're using the other variant:
    >
    > -(void) setFont: (NSFont*)f
    > {
    > [font autorelease];
    > font = [f retain];
    > }
    >
    > This will release an object that was never retained by you, thus
    > effectively also failing to do the additional "retain" needed to give
    > your copy ownership of the NSFont. Apple recommends to do:
    >
    > -(id) copyWithZone: (NSZone*)zone
    > {
    > MyClass *newCell = [super copyWithZone: zone];
    >
    > newCell->font = nil;
    > [newCell setFont: font];
    >
    > newCell->subString = nil;
    > [newCell setSubString: subString];
    >
    > return newCell;
    > }
    >
    > --
    >
    >
    > Cheers,
    > M. Uli Kusterer
    > ------------------------------------------------------------
    > "The Witnesses of TeachText are everywhere..."
    > http://www.zathras.de
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<jolivierld...>
    >
    > This email sent to <jolivierld...>
    >

    --
    --Olivier
  • Why don't you check the crash log or run the application in the
    debugger until it crashes. You'll get a stack trace from which will
    help you pinpoint the problem.

    - Byron

    On Nov 5, 2004, at 3:27 PM, Jean-Olivier Lanctôt wrote:

    > Well I just learned a new thing...
    >
    > anyway, I have this very WEIRD crash in my app (which is, BTW, the
    > ONLY bug left until I can release 1.0) that I just can't squash.
    > *Maybe* it has to do with my wrong manner of overriding copyWithZone??
    > What do you guys think.. I have something like 5 custom classes
    > implementing it and I don't do it the right way... so could that be
    > the reason for weird crashes? I'm not on my work comp. right now so I
    > can't check.
    >

    Byron Wright
    Software Developer
    Siemens Business Services Media
    (formerly BBC Technology)
    www.bbctechnology.com
    www.siemens.co.uk/sbs

    This e-mail (and any attachments) contains confidential information and
    is for the exclusive use of the addressee/s. Any views contained in
    this e-mail are not the views of Siemens Business Services Media
    Holdings Ltd unless specifically stated. If you are not the addressee,
    then any distribution, copying or use of this e-mail is prohibited. If
    received in error, please advise the sender and delete/destroy it
    immediately. We accept no liability for any loss or damage suffered by
    any person arising from use of this e-mail/fax. Please note that
    Siemens Business Services Media Holdings Ltd monitors e-mails sent or
    received. Further communication will signify your consent to this.

    Siemens Business Services Media Holdings Ltd
    Registered No: 04128934 England
    Registered Office: Siemens House, Oldbury, Bracknell, Berkshire, RG12
    8FZ
  • Yes well. I'm not a newbie (far from it, I'd say ;-). I already did
    that... etc etc. The bug has been around since a LONG time and I
    haven't been able to fix it!

    It's crashing upon collapse of the LAST item in my outlineview...
    here's the BT...
    i'm about to just hire someone to do it for me.. I just can't see WHY
    it does this.

    Thread 0 Crashed:
    0  com.apple.CoreFoundation    0x90190f9c CFRetain + 0x20
    1  com.apple.CoreFoundation    0x9019cb2c CFDictionaryAddValue + 0x1f4
    2  com.apple.CoreFoundation    0x901ae434 CFDictionaryCreate + 0x6c
    3  com.apple.Foundation        0x909fbcdc -[NSPlaceholderDictionary
    initWithObjects:forKeys:count:] + 0xf4
    4  com.apple.Foundation        0x90a00fe0 +[NSDictionary
    dictionaryWithObjectsAndKeys:] + 0x144
    5  com.apple.AppKit            0x930b8388 -[NSOutlineView
    _postItemDidCollapseNotification:] + 0x5c
    6  com.apple.AppKit            0x930b6e48 -[NSOutlineView
    _collapseItemEntry:collapseChildren:clearExpandState:recursionLevel:]
    + 0x208
    7  com.apple.AppKit            0x930b6b74 -[NSOutlineView
    _collapseItem:collapseChildren:clearExpandState:] + 0x158
    8  com.apple.AppKit            0x930b93a0 -[NSOutlineView
    collapseItem:collapseChildren:] + 0x7c
    9  com.apple.AppKit            0x930b7e28 -[NSOutlineView
    _doUserExpandOrCollapseOfItem:isExpand:optionKeyWasDown:] + 0x3a0
    10  com.apple.AppKit            0x930b9aa0 -[NSOutlineView
    mouseTracker:didStopTrackingWithEvent:] + 0x104
    11  com.apple.AppKit            0x92f9db08 -[NSMouseTracker
    stopTrackingWithEvent:] + 0xb8
    12  com.apple.AppKit            0x92f9d1ac -[NSMouseTracker
    trackWithEvent:inView:withDelegate:] + 0x164
    13  com.apple.AppKit            0x92f38670 -[NSOutlineView mouseDown:] + 0x274
    14  com.clichedev.burnoutmenu  0x00021b30 -[BMManagerOutlineView
    mouseDown:] + 0x64 (BMManagerOutlineView.m:57)
    15  com.apple.AppKit            0x92e024d4 -[NSWindow sendEvent:] + 0x10e4
    16  com.apple.AppKit            0x92df4b98 -[NSApplication sendEvent:] + 0xebc
    17  com.apple.AppKit            0x92dfcfb0 -[NSApplication run] + 0x240
    18  com.apple.AppKit            0x92eb948c NSApplicationMain + 0x1d0
    19  com.clichedev.burnoutmenu  0x00003234 main + 0x6c (main.m:23)
    20  com.clichedev.burnoutmenu  0x00002cb8 _start + 0x188 (crt.c:267)
    21  dyld                        0x8fe1a558 _dyld_start + 0x64

    On Fri, 5 Nov 2004 15:39:30 -0800, Byron Wright
    <byron...> wrote:
    > Why don't you check the crash log or run the application in the
    > debugger until it crashes. You'll get a stack trace from which will
    > help you pinpoint the problem.
    >
    > - Byron
    >
    >
    >
    > On Nov 5, 2004, at 3:27 PM, Jean-Olivier Lanctôt wrote:
    >
    >> Well I just learned a new thing...
    >>
    >> anyway, I have this very WEIRD crash in my app (which is, BTW, the
    >> ONLY bug left until I can release 1.0) that I just can't squash.
    >> *Maybe* it has to do with my wrong manner of overriding copyWithZone??
    >> What do you guys think.. I have something like 5 custom classes
    >> implementing it and I don't do it the right way... so could that be
    >> the reason for weird crashes? I'm not on my work comp. right now so I
    >> can't check.
    >>
    >
    > Byron Wright
    > Software Developer
    > Siemens Business Services Media
    > (formerly BBC Technology)
    > www.bbctechnology.com
    > www.siemens.co.uk/sbs
    >
    > This e-mail (and any attachments) contains confidential information and
    > is for the exclusive use of the addressee/s. Any views contained in
    > this e-mail are not the views of Siemens Business Services Media
    > Holdings Ltd unless specifically stated. If you are not the addressee,
    > then any distribution, copying or use of this e-mail is prohibited. If
    > received in error, please advise the sender and delete/destroy it
    > immediately. We accept no liability for any loss or damage suffered by
    > any person arising from use of this e-mail/fax. Please note that
    > Siemens Business Services Media Holdings Ltd monitors e-mails sent or
    > received. Further communication will signify your consent to this.
    >
    > Siemens Business Services Media Holdings Ltd
    > Registered No: 04128934 England
    > Registered Office: Siemens House, Oldbury, Bracknell, Berkshire, RG12
    > 8FZ
    >
    >

    --
    --Olivier
  • I think one fine point has been missed until now (not sure what the
    Apple docs have to say on it). If you derive from NSObject, you should
    not call [[MyClass alloc] init] but [[[self class] alloc] init] to get
    an instantiation of the right subclass. This might be causing your
    problems...

    Regards

        Steven

    --
    <steven...>
    http://sprintteam.nl/

    Op 6-nov-04 om 0:27 heeft Jean-Olivier Lanctôt het volgende geschreven:

    > Well I just learned a new thing...
    >
    > anyway, I have this very WEIRD crash in my app (which is, BTW, the
    > ONLY bug left until I can release 1.0) that I just can't squash.
    > *Maybe* it has to do with my wrong manner of overriding copyWithZone??
    > What do you guys think.. I have something like 5 custom classes
    > implementing it and I don't do it the right way... so could that be
    > the reason for weird crashes? I'm not on my work comp. right now so I
    > can't check.
    >
  • At 15:39 Uhr -0800 05.11.2004, Byron Wright wrote:
    > Why don't you check the crash log or run the application in the
    > debugger until it crashes. You'll get a stack trace from which will
    > help you pinpoint the problem.

      Though with memory bugs, the time at which you see the crash might
    not be the time at which the actual bug occurred. If you overwrite
    some memory, and it's still within your app's allocated range of
    addresses, you won't notice until you next attempt to use the
    overwritten data.

      Most "weird" crashes are memory-related.
    --
    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
            "The Witnesses of TeachText are everywhere..."
                        http://www.zathras.de
  • Not to rain on the parade but NSCopying does explain that you should
    implement this method with one of the three available ways.

    1. Super implements it and you want a deep copy. So you call [super
    allocWithZone:] and use the memory selectors to set the elements that
    your subclass adds.
    ie.
    -(id) copyWithZone: (NSZone*)zone {
          MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    need to cast up to your subclass

    // then set your memory state using the memory selectors and copy
          newCell->font = [font copy];
          newCell->subString = [subString copy];

          return newCell;
    }

    2. Your super does not implement it. So you manually call [[self
    allocWithZone:] init] and use the set/get methods to set your state.

    -(id) copyWithZone: (NSZone*)zone {
          MyClass *newCell = [[self allocWithZone:zone] init]; // we know
    how to do this thanks to NSObject

    // then set your memory state using the set/get methods we made
    // Depending on teh implementation of your class these will most
    likely be shallow copies
    // Unless your mutators copy incoming state and return copies of
    internal state to
    // provide another level of encapsulation
          [newCell setFont:font];
          [newCell setSubString:subString];

          return newCell;
    }

    3. And last but not least, LIE. To be honest cells are supposed to be
    lightweight and fast so why spend time copying immutable state
    variables, instead we just point to the ones we already have?

    -(id) copyWithZone: (NSZone*)zone {
          MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    need to cast up to your subclass

    // then set your memory state using the memory selectors and point to
    what you already have
          newCell->font = font;
          newCell->subString = subString;

          return newCell;
    }

    The last method is good since it's MUCH faster and NSCells are
    instantiated then their -setObjectValue: is called so this gets
    changed anyway. However, this also lets you know when something is
    wrong since all your cells look the same and have the same info for
    whatever reason that is probably -willDisplayCell related. Yea,  i
    make a lot of custom cells.

    On Sat, 6 Nov 2004 16:50:01 +0100, M. Uli Kusterer
    <witness.of.teachtext...> wrote:
    > At 15:39 Uhr -0800 05.11.2004, Byron Wright wrote:
    >> Why don't you check the crash log or run the application in the
    >> debugger until it crashes. You'll get a stack trace from which will
    >> help you pinpoint the problem.
    >
    > Though with memory bugs, the time at which you see the crash might
    > not be the time at which the actual bug occurred. If you overwrite
    > some memory, and it's still within your app's allocated range of
    > addresses, you won't notice until you next attempt to use the
    > overwritten data.
    >
    > Most "weird" crashes are memory-related.
    > --
    >
    >
    > Cheers,
    > M. Uli Kusterer
    > ------------------------------------------------------------
    > "The Witnesses of TeachText are everywhere..."
    > http://www.zathras.de
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<karl.adam...>
    >
    > This email sent to <karl.adam...>
    >
  • oops, sent in what would definetely crash your apps, the LIEing
    technique retains the elements rather than just sets them because
    otherwise when they do get set and it was released in one place, it
    would crash for no longer being valid elsewhere.

    The 3rd example should read:

    -(id) copyWithZone: (NSZone*)zone {
            MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    need to cast up to your subclass

    // then set your memory state using the memory selectors and point to
    what you already have
            newCell->font = [font retain];
            newCell->subString = [subString retain];

            return newCell;
    }

    On Mon, 8 Nov 2004 20:04:13 -0500, The Karl Adam <karl.adam...> wrote:
    > Not to rain on the parade but NSCopying does explain that you should
    > implement this method with one of the three available ways.
    >
    > 1. Super implements it and you want a deep copy. So you call [super
    > allocWithZone:] and use the memory selectors to set the elements that
    > your subclass adds.
    > ie.
    > -(id) copyWithZone: (NSZone*)zone {
    > MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    > need to cast up to your subclass
    >
    > // then set your memory state using the memory selectors and copy
    > newCell->font = [font copy];
    > newCell->subString = [subString copy];
    >
    > return newCell;
    > }
    >
    > 2. Your super does not implement it. So you manually call [[self
    > allocWithZone:] init] and use the set/get methods to set your state.
    >
    > -(id) copyWithZone: (NSZone*)zone {
    > MyClass *newCell = [[self allocWithZone:zone] init]; // we know
    > how to do this thanks to NSObject
    >
    > // then set your memory state using the set/get methods we made
    > // Depending on teh implementation of your class these will most
    > likely be shallow copies
    > // Unless your mutators copy incoming state and return copies of
    > internal state to
    > // provide another level of encapsulation
    > [newCell setFont:font];
    > [newCell setSubString:subString];
    >
    > return newCell;
    > }
    >
    > 3. And last but not least, LIE. To be honest cells are supposed to be
    > lightweight and fast so why spend time copying immutable state
    > variables, instead we just point to the ones we already have?
    >
    > -(id) copyWithZone: (NSZone*)zone {
    > MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    > need to cast up to your subclass
    >
    > // then set your memory state using the memory selectors and point to
    > what you already have
    > newCell->font = font;
    > newCell->subString = subString;
    >
    > return newCell;
    > }
    >
    > The last method is good since it's MUCH faster and NSCells are
    > instantiated then their -setObjectValue: is called so this gets
    > changed anyway. However, this also lets you know when something is
    > wrong since all your cells look the same and have the same info for
    > whatever reason that is probably -willDisplayCell related. Yea,  i
    > make a lot of custom cells.
    >
    > On Sat, 6 Nov 2004 16:50:01 +0100, M. Uli Kusterer
    >
    >
    > <witness.of.teachtext...> wrote:
    >> At 15:39 Uhr -0800 05.11.2004, Byron Wright wrote:
    >>> Why don't you check the crash log or run the application in the
    >>> debugger until it crashes. You'll get a stack trace from which will
    >>> help you pinpoint the problem.
    >>
    >> Though with memory bugs, the time at which you see the crash might
    >> not be the time at which the actual bug occurred. If you overwrite
    >> some memory, and it's still within your app's allocated range of
    >> addresses, you won't notice until you next attempt to use the
    >> overwritten data.
    >>
    >> Most "weird" crashes are memory-related.
    >> --
    >>
    >>
    >> Cheers,
    >> M. Uli Kusterer
    >> ------------------------------------------------------------
    >> "The Witnesses of TeachText are everywhere..."
    >> http://www.zathras.de
    >> _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/<karl.adam...>
    >>
    >> This email sent to <karl.adam...>
    >>
    >
  • At 20:04 Uhr -0500 08.11.2004, The Karl Adam wrote:
    > -(id) copyWithZone: (NSZone*)zone {
    > MyClass *newCell = [[self allocWithZone:zone] init]; // we know
    > how to do this thanks to NSObject

      Here's a typo: This should be [self class]. allocWithZone: is a
    class method, not an instance method.

    > -(id) copyWithZone: (NSZone*)zone {
    > MyClass *newCell = (MyClass *)[super copyWithZone:zone]; // you
    > need to cast up to your subclass
    >
    > // then set your memory state using the memory selectors and point to
    > what you already have
    > newCell->font = font;
    > newCell->subString = subString;
    >
    > return newCell;
    > }

      This is buggy as well. You can't just assign font and subString when
    they are objects, because usually your class will need to retain
    them. So this should be:

    newCell->font = [font retain];
    newCell->subString = [subString retain];

    or, if you follow the recommendation from many pros that you should
    *always* use accessors to manipulate your variables, you should do
    what Apple does in its sample code:

    newCell->font = nil;
    [newCell setFont: font];
    newCell->subString = nil;
    [newCell setSubString: subString];

    Again, remember that the nil assignment is necessary if the super
    calls NSCopyObject(), which performs a shallow copy, meaning there
    are un-retained pointers in those variables. However, you can only do
    this if you know that super calls NSCopyObject, because if it just
    calls allocWithZone and init, then these pointers have already been
    retained, and you actually need to use the accessor to ensure the old
    value is released and the new one retained.

      Don't ask me why it's so complicated. I guess NSCopyObject() was
    created for classes that mostly contain data and few pointers to
    objects.
    --
    Cheers,
    M. Uli Kusterer
    ------------------------------------------------------------
            "The Witnesses of TeachText are everywhere..."
                        http://www.zathras.de