Problem With implementing copyWithZone

  • Hello All --

    I have a subclass of NSManagedObject that I am trying to implement
    copyWithZone in. I would have thought that this would be a simple
    process based on my research in the archives of the mailing list. I
    found the following snippet of code which I adapted for my own purposes:

    - (id)copyWithZone:(NSZone *)zone {
    id copy = [[[self class] allocWithZone:zone] init];
    [copy setThisAttribute:[self getThisAttribute]];
    [copy setThatAttribute:[self getThatAttribute]];

    return copy;
    }

    My implementation looks like:

    - (id) copyWithZone:(NSZone *)zone {
    id copiedWine;

    copiedWine = [[[self class] allocWithZone:zone] init];
    // [copiedWine setVineyard:[self vineyard]];
    // [copiedWine setValue:[self valueForKey:@"vineyard"]
    forKey:@"vineyard"];
    [copiedWine setVineyard:[self valueForKey:@"vineyard"]];

    return(copiedWine);
    }

    When the method is called I get the following error:

    2007-10-07 18:12:40.205 WineCellar[5988:10b] *** Terminating app due
    to uncaught exception 'NSUnknownKeyException', reason: '[<Wine
    0x174027e0> setValue:forUndefinedKey:]: the entity (null) is not key
    value coding-compliant for the key vineyard.'
    2007-10-07 18:12:40.206 WineCellar[5988:10b] Stack: (
        2477803064,
        2426327195,
        2477801825,
        2458935672,
        2470635448,
        79584,
        86877,
        2416367608,
        2416450382,
        2416450119,
        2418600087,
        2418598909,
        2419265892,
        2419265553,
        2417649629,
        2417136543,
        2417135976,
        2417133214,
        2416761814,
        2416756412,
        2417346575,
        2417341342,
        2417342197,
        2417342197,
        2417342197,
        2417342197,
        2417342197,
        2417342197,
        2417335548,
        2417333822,
        2417320300,
        2416538197,
        2416537092,
        2417304252,
        2417302802,
        2417506539,
        2416334426,
        2416293791,
        2416292097,
        2416291140,
        2416290946,
        2416290097,
        9060,
        8986
    )

    There are accessor methods in the class are defined as:

    - (NSString *) vineyard;
    - (void) setVineyard:(NSString *)value;

    I'm not sure what I'm doing wrong here, but if anyone has a
    suggestion as to how to fix this problem I would be grateful.

    Thanks very much.

    Thaddeus O. Cooper
    (<tcooper...>)
  • On Oct 7, 2007, at 6:25 PM, Thaddeus Cooper wrote:

    > My implementation looks like:
    >
    > - (id) copyWithZone:(NSZone *)zone {
    > id    copiedWine;
    >
    > copiedWine = [[[self class] allocWithZone:zone] init];

    The designated initializer for NSManagedObject is -
    initWithEntity:insertIntoManagedObjectContext: and not -init as your
    code assumes.  This means that your instance doesn't know what its
    entity is, and therefore doesn't know what properties it has, which
    leads to this exception:

    > 2007-10-07 18:12:40.205 WineCellar[5988:10b] *** Terminating app due
    > to uncaught exception 'NSUnknownKeyException', reason: '[<Wine
    > 0x174027e0> setValue:forUndefinedKey:]: the entity (null) is not key
    > value coding-compliant for the key vineyard.'

    Also, you have to be extremely careful in determining what, exactly,
    it means to "copy" an instance of your entity.  Does it mean to create
    a new, identical instance of that entity with both the same attributes
    *and* the same relationships?  What if your entity has relationships
    with to-one inverses?  Do you copy the entire object graph rooted at
    that object?  If so, what if the object graph isn't strictly
    hierarchical?

      -- Chris
  • Chris thanks for the great information.

    If I understand -initWithEntity:insertIntoManagedObjectContext: then
    it will create an object in the store -- which I don't believe I
    want. I am only implementing copyWithZone: because  it is required
    for the composite NSCell subclass that I am working on which combines
    multiple pieces of data from an NSManagedObject subclass into a
    single cell, so I believe that I want an absolute duplicate of what
    is already in the store.

    A little background. What I am trying to do is create a cell that is
    used in the column of a table to show multiple pieces of data from an
    NSManagedObject so that the user has a high level overview of the
    information without having to plow through a lot of columns. So I
    tried using an NSTextFieldCell as the class from which I subclassed
    my new class because the data is mostly text with some icons, but the
    data returned by objectValue was the description string of the
    NSManagedObject (using the binding arrangedObjects.self) which isn't
    what I wanted (I want the actual NSMangedObject), so as an experiment
    I decided to use NSCell instead, but that requires copyWithZone: to
    be implemented. And here I am. :-(

    So either the way I am binding the cell in the table view is wrong,
    or I am thinking about the NS[TextField]Cell subclass incorrectly. I
    know I'm not the first one down this path, but I have not been able
    to find much documentation about this, so If you or anyone else has a
    suggestion as to how to proceed once again I'd be really grateful.

    Thanks very much.

    Thaddeus O. Cooper
    (<tcooper...>)

    On Oct 7, 2007, at 7:47 PM, Chris Hanson wrote:

    > On Oct 7, 2007, at 6:25 PM, Thaddeus Cooper wrote:
    >
    >> My implementation looks like:
    >>
    >> - (id) copyWithZone:(NSZone *)zone {
    >> id    copiedWine;
    >>
    >> copiedWine = [[[self class] allocWithZone:zone] init];
    >
    > The designated initializer for NSManagedObject is -
    > initWithEntity:insertIntoManagedObjectContext: and not -init as
    > your code assumes.  This means that your instance doesn't know what
    > its entity is, and therefore doesn't know what properties it has,
    > which leads to this exception:
    >
    >> 2007-10-07 18:12:40.205 WineCellar[5988:10b] *** Terminating app
    >> due to uncaught exception 'NSUnknownKeyException', reason: '[<Wine
    >> 0x174027e0> setValue:forUndefinedKey:]: the entity (null) is not
    >> key value coding-compliant for the key vineyard.'
    >
    > Also, you have to be extremely careful in determining what,
    > exactly, it means to "copy" an instance of your entity.  Does it
    > mean to create a new, identical instance of that entity with both
    > the same attributes *and* the same relationships?  What if your
    > entity has relationships with to-one inverses?  Do you copy the
    > entire object graph rooted at that object?  If so, what if the
    > object graph isn't strictly hierarchical?
    >
    > -- Chris
    >
  • On Oct 7, 2007, at 8:16 PM, Thaddeus Cooper wrote:

    > I am only implementing copyWithZone: because  it is required for the
    > composite NSCell subclass that I am working on which combines
    > multiple pieces of data from an NSManagedObject subclass into a
    > single cell, so I believe that I want an absolute duplicate of what
    > is already in the store.

    In implementing an NSCell subclass, you do need to consider how to
    handle the NSCopying and NSCoding protocol methods.  However, you
    shouldn't need to copy the value of the cell, only the cell itself.
    (After all, the NSCell value properties like objectValue are
    implemented by NSCell, so any copying of them would be handled by
    NSCell itself if it was actually desired.)

      -- Chris
  • On 8-Oct-07, at 12:23 PM, Chris Hanson wrote:

    > On Oct 7, 2007, at 8:16 PM, Thaddeus Cooper wrote:
    >
    >> I am only implementing copyWithZone: because  it is required for
    >> the composite NSCell subclass that I am working on which combines
    >> multiple pieces of data from an NSManagedObject subclass into a
    >> single cell, so I believe that I want an absolute duplicate of
    >> what is already in the store.

    I also recently ran across the mysterious missing copyWithZone: when
    trying to use a custom NSCell with NSManagedObjects.

    I blogged about it at:
    http://kupuk.com/2007/10/08/custom-nscells-with-nsmanagedobjects/

    The short answer is that you need to override the setObjectValue:
    method (which tries to copy your uncopyable NSManagedObject) in your
    custom NSCell to convert your NSManagedObject into an NSValue (which
    is copyable).

    Paul
previous month october 2007 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 31        
Go to today