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...>


