Objective-C Property - Difference Between Retain and Assign - objective-c

I think I am missing something about property attributes.
First, I can't understand the difference between retain and assign.
If I use assign, does the property increase the retain counter by 1 to the setter and also to the getter, and do I need to use release to both of them?
And how does this work with readwrite or copy? From the view of a retain count.
I am trying to understand when i need to use release after working with a property (setter and getter)
#property (readwrite,assign) int iVar;
What does assign do here?
What is the difference between:
#property (readwrite,assign) int iVar;
and
#property (readwrite,retain) int iVar;
and
#property (readwrite) int iVar;
Many thanks...

what is the different between : #property (readwrite,assign) int iVar; to #property (readwrite,retain) int iVar; to #property (readwrite) int iVar;
The setter for #property (readwrite,assign) sometype aProperty; is semantically equivalent to
-(void) setAProperty: (sometype) newValue
{
ivar = newValue;
}
The above is more or less what you will get if you put
#asynthesize aProperty = ivar;
in your implementation.
The setter for #property (readwrite,retain) sometype aProperty; is semantically equivalent to
-(void) setAProperty: (sometype) newValue
{
[newValue retain];
[ivar release];
ivar = newValue;
}
Clearly, it makes no sense to retain or release an int, so sometype must be either id or SomeObjectiveCClass*
The setter for #property (readwrite,copy) sometype aProperty; is semantically equivalent to
-(void) setAProperty: (sometype) newValue
{
sometype aCopy = [newValue copy];
[ivar release];
ivar = aCopy;
}
In this case, not only must sometype be an objective C class but it must respond to -copyWithZone: (or equivalently, implement NSCopying).
If you omit retain or assign or copy, the default is assign.
By the way, I have simplified the above by not considering the locking that occurs because the properties don't also specify nonatomic.

There are two kind of specifiers:
The readwrite specifier tells that the property will be read/write, so when you do a # synthesize it will create both the getter and the setter.
There's also readonly, to specify that the property will only have a getter.
The other modifiers specify how the properties will behave respect of the reference counting:
The assign modifier, tells that the ivar will simply be assigned with whatever the setter receives. So, in case of an object, retain won't be called.
With retain, whenever you use the synthesized setter, retain will be called, so the object will be retained. This means that the class that has the setter needs to release it at some point (probably in its dealloc method).
As for copy, it means that instead of retain, the object will receive a copy message. This means that you'll end up with a copy of the original object, with a retain count of one, so again, you are responsible of releasing it.

Related

In ObjectiveC, is it necessary to declare strong vs copy for a readonly property?

In Objective-C, it's common to declare NSString/NSArray/NSDictionary as copy, is it necessary to do that for a readonly property or there is no difference? If an NSString is readonly, it will never be set, so declaring it strong or copy will have the same effect right?
//use strong rather copy here and it will work the same since it will
never be copied?
#property (nonatomic, readonly) NSString *string;
If it really is read-only then you don't need to specify it. If you're going to redeclare it privately to be readwrite then you do want to specify it. For readonly properties it has no effect as no setter will be created.
You're right, but there're some things to consider. That's okay as long, as your property is immutable object. However, it is not always true.
First example, which I run into frequently, is when you have actually mutable object inside of your implementation. Like property declared NSArray in implementation can actually be NSMutableArray. Strong reference property getter for it will return pointer to that NSMutableArray. And, at some point, you'll run into situation when you request NSArray from object, work with it some time and than - boom!!! - your NSArray have different elements of number of it? What the hell? In that case, it's better idea to copy your inner implementation used NSMutableArray in getter.
Another example is some model object
#interface Person : NSObject <NSCopying>
#property NSString *name;
#property NSDate *birthdate;
#end
And you have some other interface with property
#property (strong, readonly) Person *person;
Yeah, you will not assign different object to this property. However, you'll be able to modify its fields, so it will represent some completely different Person. If you don't want such behaviour - make it copy property. Or make it private with access methods to get its fields
- (id) getHiddenPersonPropertyValueForKey:(NSString *)personPropertyKey;
Or any other way
If property represents really immutable value (NSArray, NSIndexSet, etc), then just readonly is fine, as it will be returned immutable as-is.
But in case of your private ivar being mutable (NSMutableArray ivar vs property's NSArray type), you should return a copy to prevent leaks of future internal changes into caller's state.
#interface MyObject : NSObject {
NSMutableArray *_array;
}
#property(nonatomic, readonly) NSArray *array;
// -or-
- (NSArray *)array;
#end
and
#implementation
#dynamic array; // only if #property was declared in interface
- (NSArray *)array
{
return [_array copy];
}
#end
The caller is safe then to store property's value and expect that it will not change even without making explicit copy itself:
self.array = [myObject array]; // e.g. 1 element
[myObject addElementToArray:#(42)];
NSLog(#"%#", self.array); // still 1 element

What's the difference the member variable between in a interface and #property (nonatomic, strong)?

#interface ChargeView (){
NSString* billid;
int clickRow;
NSMutableArray *arr1;
}
#property (nonatomic, strong) NSMutableArray *arr2;
What's the difference between arr1 and arr2? Which is better or write it anywhere if I like?
The property also generates the accessors -(NSMutableArray *)arr2 (getter) and -(void)setArr2:(NSMutableArray *)arr2 (setter). It further generates a corresponding instance variable _arr2 (the underscore is convention for ivars). The attributes of the property determine the behavior of the accessors. For instance, if the property is marked atomic, the accessors will synchronize access to the ivar.
On the other hand, arr1 is just an ivar and you have to write accessors (if you need any) yourself.

Do properties default to nil?

If i don't use an ivar for properties, but do this:
#interface someClass : NSObject
#property (nonatomic, retain) NSArray * someArray;
#end
#implementation someClass
#synthesize someArray = _someArray;
- (void) someMethod
{
if( self.someArray == nil ){
// True on the first call?
}
}
#end
The first time I check self.someArray it returns nil, as does _someArray, but is this guaranteed? I read only that ivars are guaranteed to be nil, and since I don't declare a ivar (_someArray is not an ivar), I am not sure if it will be nil everywhere and every time.
It's always nil. Objective-C initialises all the variables in a class to nil when it is allocated. Synthesised ivars follow the same rules.
Properties are backed by instance variables if they are synthesized automatically -- so yes, by default such properties will return nil.
Yes, all properties, ivars and static variables have always been defined to be initialized to nil. Now with ARC this carries over to __strong stack variables (__strong being the default for all object pointers).

CGImageRef property retain or not retain

I have a question on how to handle a CGImageRef as a synthesized property of a class.
If I define an CGImageRef with
#property (nonatomic, retain) CGImageRef image;
then the compiler complains that "retain" cannot be used here. If I leave out the retain, then I assume "assign" is used instead, and I need to do the retain myself when I set the property:
self.image = CGImageRetain ( cgimage );
then I get an "Potential leak" warning when running Analyze. Can I safely ignore this warning? Or does the synthesize code do an implicit CGRetain anyways, even though no "retain" is specified in the property definition?
What you want to do is add an annotation to the property that the type really can be retained.
Change the property declaration to
#property (nonatomic, retain) CGImageRef image __attribute__((NSObject));
Note that this will only generate the getters and setters for you, the instance variable itself is not ARC controlled. Specifically, this means that you must release it in dealloc, and that you need to use proper retain and release when assigning directly to the instance variable.
A better approach may be to use a typedef:
typedef CGImageRef CGImageObject __attribute__((NSObject));
#property (nonatomic, retain) CGImageObject image;
In this case, the instance variable is controlled by ARC, and so you must not release it in dealloc, and direct assignments to the instance variable are handled by ARC as well.
For reference, see the specification, specifically section 4.1.1:
Applying __attribute__((NSObject)) to a property not of retainable
object pointer type has the same behavior it does outside of ARC: it
requires the property type to be some sort of pointer and permits the
use of modifiers other than assign. These modifiers only affect the
synthesized getter and setter; direct accesses to the ivar (even if
synthesized) still have primitive semantics, and the value in the ivar
will not be automatically released during deallocation.
and section 3:
A retainable object pointer (or “retainable pointer”) is a value of a
retainable object pointer type (“retainable type”). There are three
kinds of retainable object pointer types:
block pointers (formed by applying the caret (^) declarator sigil to a
function type)
Objective-C object pointers (id, Class, NSFoo*, etc.)
typedefs marked with __attribute__((NSObject))
I don't like to instruct the compiler when compiling. I think it's ugly. I'd override the methods myself.
#interface MyClass : NSObject {
CGImageRef _image;
}
#property (nonatomic, assign) CGImageRef image;
#end
#implementation MyClass
- (void)setImage:(CGImageRef)i {
if(_image != i) {
CGImageRelease(_image);
_image = CGImageRetain(i);
}
}
- (CGImageRef)image {
return _image;
}
#end
How about this?
#property (nonatomic, setter=setImage:) CGImageRef image;
(void)setImage:(CGImageRef)image {
if (_image != image) {
CGImageRelease(_image);
_image = CGImageRetain(image);
}
}

Do the ARC compiler automatically determines whether to retain or assign in overridden class depending on property attributes?

I don't know assembler well enough to understand so complicated code as Assembly for whole project, but I noticed that if I put strong attribute to the property, a _objc_storeStrong call shows up near the line in my setter where I change my properly;
#interface ClassName : NSObject
#property (strong, nonatomic) NSSet *mySet;
#end
#implementation ClassName
#synthesize mySet;
-(void)setMySet:(NSSet *)newMySet
{
mySet = newMySet;
//do stuff
}
#end
So? am I right? Do the ARC compiler automatically determines whether to retain or assign in overridden class depending on property attributes?
In short, yes. Because you set the property as strong, it will be retained by the object. If you declare the property as weak, the implied (synthesized) variable is __weak NSSet *mySet and that won't retain the object, but it will be a auto-zeroing pointer.