Curious about copyWithZone message from NSArrayController in "GC required" project

  • Hi all,

    I have a "gc required" project with some entities in a CoreData model,
    each with requisite subclasses of NSManagedObject.
    In particular, I have an entity/class 'A' that declares a property
    returning an NSArray (which actually returns an ordered list of entity/
    class 'B' that is defined as a to-many relationship on the entity A).
    Now, in my UI, I have a couple of NSArrayControllers.  One of these
    obtains the 'A's from the managed object context, and provides
    instances to UI that in turn uses an NSArrayController bound to the
    property of 'A', such that all the 'B's of a given 'A' are returned in
    the correct order.

    Now, all this is now working correctly (as far as I can tell), but
    before I got it to work as expected, I had to fix a problem logged in
    the console as:
    *** -[B copyWithZone:]: unrecognized selector sent to instance 0x127f310

    The obvious fix of implementing a 'dumb' copyWithZone in the B class
    (that returns B's 'self' ) got past the problem, but it raises a
    number of questions in my Cocoa n00b's mind:
    1. Why am I being asked to create a copy of B instances anyway?  I
    would have thought that NSArrayController could work quite happily
    with a reference to my original B's - at least in the GC context.
    Indeed, forcing this to happen with a trivial implementation of
    copyWithZone seems to work happily.
    2. Is this something I could change through a configuration in my
    code?  I had a property declaration array of B's returnable from A
    (readonly), and I have tried both retain and assign to see if this
    would affect anything (it didn't).
    3. In general, am I _supposed_ to support the NSCopying protocol on my
    classes (even knowing that they will only ever be using in GC) as a
    matter of course.  I can certainly think of scenarios where one might
    like to clone/deepCopy object trees, but had not (yet) read anything
    in the docs that suggests a requirement to do this as a matter of
    course in order to use collections and collection controllers.  I have
    been using instances of these classes in all sorts of collections up
    to now, with no hint of having to implement copyWithZone.

    -- Lwe
  • On Jan 12, 2008, at 8:03 PM, Luke Evans wrote:
    > I have a "gc required" project with some entities in a CoreData
    > model, each with requisite subclasses of NSManagedObject.
    > In particular, I have an entity/class 'A' that declares a property
    > returning an NSArray (which actually returns an ordered list of
    > entity/class 'B' that is defined as a to-many relationship on the
    > entity A).
    > Now, in my UI, I have a couple of NSArrayControllers.  One of these
    > obtains the 'A's from the managed object context, and provides
    > instances to UI that in turn uses an NSArrayController bound to the
    > property of 'A', such that all the 'B's of a given 'A' are returned
    > in the correct order.
    >
    > Now, all this is now working correctly (as far as I can tell), but
    > before I got it to work as expected, I had to fix a problem logged
    > in the console as:
    > *** -[B copyWithZone:]: unrecognized selector sent to instance
    > 0x127f310
    >
    > The obvious fix of implementing a 'dumb' copyWithZone in the B class
    > (that

    First and foremost, -copyWithZone: has absolutely nothing to do with
    the differences between GC and non-GC.  As its name implies, it is all
    about copying an object, something that must be done in either GC or
    non-GC.

    > returns B's 'self' ) got past the problem, but it raises a number of
    > questions in my Cocoa n00b's mind:
    > 1. Why am I being asked to create a copy of B instances anyway?  I
    > would have thought that NSArrayController could work quite happily
    > with a reference to my original B's - at least in the GC context.
    > Indeed, forcing this to happen with a trivial implementation of
    > copyWithZone seems to work happily.

    If you are ever causing a -copyWithZone: to be sent to an
    NSManagedObject or subclass therein, then there is something seriously
    wrong with your code.

    NSManagedObjects cannot be copied via -copyWithZone: for a reason;  it
    doesn't make sense to do so without taking the model into
    consideration -- without fully traversing the relationships and
    considering exactly how the copy should be done within the bounds of
    the managed object model.

    So -- first question -- what is triggering the -copyWithZone: being
    sent to an instance of B in the first place?

    b.bum
  • Hi Bill,

    > First and foremost, -copyWithZone: has absolutely nothing to do with
    the differences between GC and non-GC.  As its name implies, it is all
    about copying an object, something that must be done in either GC or
    non-GC.

    Makes sense.  I was wondering though if the fact I had a property
    declared on A to get the array of B's made a difference.  Reading the
    docs on properties highlights some differences between GC and non-GC,
    though from what you are saying, this should not effect a copy.

    > So -- first question -- what is triggering the -copyWithZone: being
    sent to an instance of B in the first place?
    Perhaps I need to take a look to see _exactly_ who is sending the
    copyWithZone message to B, but the only time I've had this manifest is
    when I've A's property that returns the array of B's bound as the
    content of the NSArrayController - which generates some UI for the
    list of B's.  I've used put B's on all manner of collections (arrays,
    sets) directly, with no hint of anybody calling "copyWithZone".

    -- Lwe
  • On Jan 13, 2008, at 2:48 PM, Luke Evans wrote:
    >>> First and foremost, -copyWithZone: has absolutely nothing to do
    >> with the differences between GC and non-GC.  As its name implies,
    >> it is all about copying an object, something that must be done in
    >> either GC or non-GC.
    >>
    > Makes sense.  I was wondering though if the fact I had a property
    > declared on A to get the array of B's made a difference.  Reading
    > the docs on properties highlights some differences between GC and
    > non-GC, though from what you are saying, this should not effect a
    > copy.

    Only if you declared the property to use 'copy' on set.  Then, as
    expected, it would attempt to copy the object.

    >>> So -- first question -- what is triggering the -copyWithZone:
    >> being sent to an instance of B in the first place?
    >
    > Perhaps I need to take a look to see _exactly_ who is sending the
    > copyWithZone message to B, but the only time I've had this manifest
    > is when I've A's property that returns the array of B's bound as the
    > content of the NSArrayController - which generates some UI for the
    > list of B's.  I've used put B's on all manner of collections
    > (arrays, sets) directly, with no hint of anybody calling
    > "copyWithZone".

    You mentioned that you had implemented a -copyWithZone: on B?  Can
    you set a breakpoint on that and see what backtrace barfs up as a
    result?
  • O.K...

    So, I just did this and found it wasn't being called any longer.  So,
    I suspect your original intuition was right - there was something
    badly wrong with my code (which thankfully I have now rectified -
    though its frustrating not to be able to nail the original reason now).

    One change that may have had a bearing here was that I had
    inadvertently commented out some code to return an
    NSCollectionViewItem in a subclass of NSCollectionView that was
    generating UI for the B objects.  I fixed this yesterday.  It's
    possible that something in NSCollectionView was trying to do its best
    with just the prototype item and the list of B's from the
    NSArrayController.  Anyway, that's pure speculation, and perfectly
    well covered by your comment that "something is seriously wrong with
    your code"!

    I'm deleting the spurious copyWithZone now, safe in the knowledge that
    it's just not something that I should need to implement until such
    time as I have a real need for a copy constructor in that class.

    Thanks.

    -- Lwe

    On 13-Jan-08, at 2:54 PM, Bill Bumgarner wrote:

    > You mentioned that you had implemented a -copyWithZone: on B?  Can
    > you set a breakpoint on that and see what backtrace barfs up as a
    > result?
  • Closure:

    Not that this is necessarily of any use to anyone, but the "something
    seriously wrong" causing -copyWithZone to be sent to an
    NSManagedObject was the following:

    I had an NSArrayController set up to collect a set of NSManagedObjects
    from a master view selection 'upstream'.  I had then bound a table
    view to this in one of its columns, *but* I had only set the
    Controller Key (to arrangedObjects), I had not entered a Model Key
    Path i.e. set up a path to the content to be rendered in each cell of
    the column.

    Under these circumstances, the objects referenced in arrangedObjects
    (which happen to be Core Data objects) get sent a -copyWithZone.

    So this is why the problem "went away" when I had restructured my
    bindings before, I had clearly 'done the right thing' and the problem
    vanished.  I've just repeated the earlier mistake and so can report
    the reason for the message.

    -- Lwe

    On 13-Jan-08, at 3:37 PM, Luke Evans wrote:

    > O.K...
    >
    > So, I just did this and found it wasn't being called any longer.
    > So, I suspect your original intuition was right - there was
    > something badly wrong with my code (which thankfully I have now
    > rectified - though its frustrating not to be able to nail the
    > original reason now).
    >
    > One change that may have had a bearing here was that I had
    > inadvertently commented out some code to return an
    > NSCollectionViewItem in a subclass of NSCollectionView that was
    > generating UI for the B objects.  I fixed this yesterday.  It's
    > possible that something in NSCollectionView was trying to do its
    > best with just the prototype item and the list of B's from the
    > NSArrayController.  Anyway, that's pure speculation, and perfectly
    > well covered by your comment that "something is seriously wrong with
    > your code"!
    >
    > I'm deleting the spurious copyWithZone now, safe in the knowledge
    > that it's just not something that I should need to implement until
    > such time as I have a real need for a copy constructor in that class.
    >
    > Thanks.
    >
    > -- Lwe
    >
    >
    > On 13-Jan-08, at 2:54 PM, Bill Bumgarner wrote:
    >
    >> You mentioned that you had implemented a -copyWithZone: on B?  Can
    >> you set a breakpoint on that and see what backtrace barfs up as a
    >> result?

    >
previous month january 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 31      
Go to today