Use of assign vs. copy for accessors in Garbage Collected app

  • Hi -

    I'm experimenting with use of the @property declaration in a new app.
    Quite a few of my classes would be substantially simplified if this
    works as advertised.  I'm also evaluating whether this new application
    would be a good candidate for Garbage Collection.

    In reading the docs, a question came up regarding whether to use
    @property(copy) or @property(assign).  In particular the following
    text is relevant:

    > assign
    >
    > Specifies that simple assignment should be used in the setter. This
    > is the default.
    > If you use this keyword and your application does not use garbage
    > collection (GC), you get a compiler warning as this is rarely the
    > correct behavior. For non-GC applications, you must explicitly
    > specify one of the storage behavior attributes to avoid a warning
    > for objects.
    >
    > For applications that use GC, you will get a warning for this
    > attribute if the variable adopts the NSCopying protocol as assign
    > would typically be incorrect in that situation.
    >

    Can someone spell out for me why assign is bad in a GC app, and copy
    is good?  I would expect this would depend on the nature of the
    relationship between the objects being represented.  I can see how
    (copy) would make sense in many cases if the value being assigned was
    an NSString or some small and transient object.  However I also have
    cases where object A has an instance variable which is used to refer
    to another large, long-lived object B which should not be copied but
    to which a reference is necessary in object A.  In previous versions I
    would have just used assignment with the appropriate retain on the new
    object and release on the old.  Is this now wrong?

    I noticed that you get the compiler warning if you don't include any
    attribute, and "assign" is used by default in a GC app.  If you
    explicitly specify (assign), there is no warning.

    I need to know whether there may be any hidden problems in using
    @property(assign) in a GC app in cases where I don't want to copy the
    object which is input as an instance variable.  Maybe I have missed
    something about class design...

    Thanks for any comments,

    Rick
  • On Nov 27, 2007, at 7:42 PM, Rick Hoge wrote:

    >
    > Hi -
    >
    > I'm experimenting with use of the @property declaration in a new
    > app.  Quite a few of my classes would be substantially simplified if
    > this works as advertised.  I'm also evaluating whether this new
    > application would be a good candidate for Garbage Collection.
    >
    > In reading the docs, a question came up regarding whether to use
    > @property(copy) or @property(assign).  In particular the following
    > text is relevant:
    >
    >> assign
    >>
    >> Specifies that simple assignment should be used in the setter. This
    >> is the default.
    >> If you use this keyword and your application does not use garbage
    >> collection (GC), you get a compiler warning as this is rarely the
    >> correct behavior. For non-GC applications, you must explicitly
    >> specify one of the storage behavior attributes to avoid a warning
    >> for objects.
    >>
    >> For applications that use GC, you will get a warning for this
    >> attribute if the variable adopts the NSCopying protocol as assign
    >> would typically be incorrect in that situation.
    >>
    >
    > Can someone spell out for me why assign is bad in a GC app, and copy
    > is good?

    Assign isn't "bad" nor is copy "good" they just do different things
    and...

    > I would expect this would depend on the nature of the relationship
    > between the objects being represented.

    Exactly, you answered your question :)

    > I need to know whether there may be any hidden problems in using
    > @property(assign) in a GC app in cases where I don't want to copy
    > the object which is input as an instance variable.

    No hidden problems as long as potential mutation of the object
    (assuming it is mutable) isn't an issue... OK I believe one "hidden"
    issues exists when an assigned mutable object is mutated KVO will not
    trigger for that property.

    -Shawn
  • Rick Hoge wrote:
    > In reading the docs, a question came up regarding whether to use
    > @property(copy) or @property(assign). In particular the following
    > text is relevant:

    >> assign
    >> Specifies that simple assignment should be used in the setter. This
    >> is the default.
    >> If you use this keyword and your application does not use garbage
    >> collection (GC), you get a compiler warning as this is rarely the
    >> correct behavior. For non-GC applications, you must explicitly
    >> specify one of the storage behavior attributes to avoid a warning
    >> for objects.
    >>
    >> For applications that use GC, you will get a warning for this
    >> attribute if the variable adopts the NSCopying protocol as assign
    >> would typically be incorrect in that situation.
    >
    > Can someone spell out for me why assign is bad in a GC app, and copy
    > is good?

    That documentation is misleading. (Please file a bug report!)  The
    intent is more like this:

    * assign uses simple assignment in the getter
    * assign is the default
    * With GC off, you get a warning if you specify none of assign, copy,
    or retain. (This encourages you think about what memory management you
    want and type it explicitly, because the difference between `assign`
    and `retain` is large and you'll crash or leak if it's wrong.)
    * With GC on, you don't get a warning if you use the default, unless
    the property's type is a class that conforms to NSCopying. (The
    default is usually what you want; with GC the biggest difference
    between assign and retain is that retain is slower.)

    The upshot is: `assign` is usually what you want with GC, and if you
    set "Objective-C Garbage Collection = Required" in Xcode then you
    won't get the warning. "Rarely correct" is too strong for the non-GC
    case, and almost backwards for the GC case.

    > I would expect this would depend on the nature of the relationship
    > between the objects being represented. I can see how (copy) would
    > make sense in many cases if the value being assigned was an NSString
    > or some small and transient object. However I also have cases where
    > object A has an instance variable which is used to refer to another
    > large, long-lived object B which should not be copied but to which a
    > reference is necessary in object A. In previous versions I would
    > have just used assignment with the appropriate retain on the new
    > object and release on the old. Is this now wrong?

    You're right. Most properties use `assign` in GC code. You should only
    use `copy` if you actually want a copy (for example, you want
    protection against later mutation of the object).

    --
    Greg Parker    <gparker...>    Runtime Wrangler
  • I assume you mean "setter"?

    On Nov 28, 2007, at 12:05 AM, Greg Parker wrote:

    > * assign uses simple assignment in the getter
  • Thanks for this and other replies (see comments below)

    >> I'm experimenting with use of the @property declaration in a new
    >> app.  Quite a few of my classes would be substantially simplified
    >> if this works as advertised.  I'm also evaluating whether this new
    >> application would be a good candidate for Garbage Collection.
    >>
    >> In reading the docs, a question came up regarding whether to use
    >> @property(copy) or @property(assign).  In particular the following
    >> text is relevant:
    >>
    >>> assign
    >>>
    >>> Specifies that simple assignment should be used in the setter.
    >>> This is the default.
    >>> If you use this keyword and your application does not use garbage
    >>> collection (GC), you get a compiler warning as this is rarely the
    >>> correct behavior. For non-GC applications, you must explicitly
    >>> specify one of the storage behavior attributes to avoid a warning
    >>> for objects.
    >>>
    >>> For applications that use GC, you will get a warning for this
    >>> attribute if the variable adopts the NSCopying protocol as assign
    >>> would typically be incorrect in that situation.
    >>>
    >>
    >> Can someone spell out for me why assign is bad in a GC app, and
    >> copy is good?
    >
    > Assign isn't "bad" nor is copy "good" they just do different things
    > and...
    >
    >> I would expect this would depend on the nature of the relationship
    >> between the objects being represented.
    >
    > Exactly, you answered your question :)

    Ok - this is what I'd hoped.  As mentioned by another poster, the docs
    are a little ambiguous.  Will file a bug.

    >> I need to know whether there may be any hidden problems in using
    >> @property(assign) in a GC app in cases where I don't want to copy
    >> the object which is input as an instance variable.
    >
    > No hidden problems as long as potential mutation of the object
    > (assuming it is mutable) isn't an issue... OK I believe one "hidden"
    > issues exists when an assigned mutable object is mutated KVO will
    > not trigger for that property.

    Sometimes it's just necessary to refer to another object that may
    change.  Typically I register key-value observers for the properties
    of the other object I'm interested in  (e.g.  [otherObject
    addObserver:self forKeyPath:@"someIvar" options:0 context:nil];) and
    handle change notifications in

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context {
    // Handle the change here
    }

    This is tedious, but seems to work.  Of course I usually put the
    addObserver method in the setter, so automatic setter generation
    through @synthesize is of no use anyway.  However I could replace the
    verbose set/get declarations in the .h file with a more concise
    @property declaration I suppose.

    Thanks again - still trying to get my head around how these will
    actually be used in real-world apps.

    Rick

    >
    >
    > -Shawn
    >
    >
  • Hi Rick,

    On 2007-11-28, at 23:59, Rick Hoge wrote:

    > Sometimes it's just necessary to refer to another object that may
    > change.  Typically I register key-value observers for the properties
    > of the other object I'm interested in  (e.g.  [otherObject
    > addObserver:self forKeyPath:@"someIvar" options:0 context:nil];) and
    > handle change notifications in
    >
    > -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:
    > (id)object change:(NSDictionary *)change context:(void *)context

    You can also do something like:
    [self bind:@"othersIvar"
          toObject:otherObject
          forKeyPath:@"someIvar"
          options:0];

    and handle your changes in your own -(void)setOthersIvar:(id)x method.
    The advantage of this is that the setter is called as soon as you call
    the bind:... method, and the disadvantage is that you have to maintain
    a local reference to that value (or at least you *should*).

    Jonathon Mah
    <me...>
previous month november 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    
Go to today