CGImageRef property retain or not retain - objective-c

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);
}
}

Related

Overriding setter methods (strong vs. assign) using ARC

When defining a strong property in an interface, like so:
#property (nonatomic, strong) UIColor *petColor;
It is no longer required to add #synthesize, or #dynamic, or to manually define the internal ivar as _petColor, this all just works. The setters/getters are automatically generated, and you can access _petColor internally without any additional code.
However, I'm a little confused as to how (if at all), when overriding a setter, ARC knows whether to insert the retain/release calls depending on whether the property is strong or weak? For example, if I have two properties:
#property (nonatomic, strong) UIColor *petColor;
#property (nonatomic, weak) SomeClass *petDelegate;
If I want to override the setters for these properties, it seems they would be almost exactly the same?
- (void)setPetColor:(UIColor *)theColor {
if (![theColor isEqual:petColor]) {
_petColor = theColor;
}
}
- (void)setPetDelegate:(SomeClass *)theDel {
if (theDel != petDelegate) {
_petDelegate = theDel;
}
}
Is this correct? And if so, is ARC automatically inserting the proper retain/release calls in both of those setters, or only in the overridden setter for the strong property?
Further: Does the weak property behavior differ, in this situation, from the assign property behavior?
It's even simpler than that. When synthesizing, the instance variables get the respective qualifiers:
#implementation MyClass {
// this is what is added by the auto synthesize
UIColor * __strong _petColor;
SomeClass * __weak _petDelegate;
}
So when you assign to the instance variables using own setters, everything is fine, except for the copy qualifier. That one cannot be used for an instance variable, so then assign a copy to the instance variable.
Regarding assign (or the equivalent unsafe_unretained) for object properties, the instance variable would just be a pointer, and be synthesized to
SomeClass * __unsafe_unretained _petDelegate;
So if the object assigned to the property is deallocated, the pointer would not be set to nil as with weak, but point to where the deallocated object lived before. That may lead to crashes. As a rule of thumb, if you write your code for iOS 5 or later, always use weak instead of assign or unsafe_unretained on object properties.
Setting the strong, weak, or assign attributes of a property tells the compiler the storage class of the underlying data. If that is an auto-generated iVar, then it maps as following:
strong -> __strong
weak -> __weak
assign -> __unsafe_unretained
If you don't use an auto-generated iVar, then whatever data you have feeding the property is expected to conform to those storage class mappings.
See: Objective-C Automatic Reference Counting (ARC) : Property declarations

ARC forbids synthesizing a property with unspecified ownership or storage

I've created a #property of UIColor,
#property (nonatomic) UIColor *color;
and then I tried to synthesize it:
#synthesize color = _color;
but I receive an error:
ARC forbids synthesizing a property of Objective-C object with unspecified ownership or storage attribute
What does that mean?
All I'm trying to do is to create a property for a UIColor object which changes color.
Change your property declaration to:
#property (nonatomic,strong) UIColor *color;
so that ARC knows it should be retained. This would have compiled without strong before ARC but it would be dangerous since the default was assign and the color would have been released unless it was retained elsewhere.
I would highly recommend the WWDC2011 video about ARC.
You have to specify either strong or weak storage in the property declaration (next to nonatomic).

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.

property without retain with example

if we use a property without the "retain", what does it change? i have this example :
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (id)initWithCoordinate:(CLLocationCoordinate2D) coordinate;
in the .m :
-(id)initWithCoordinate:(CLLocationCoordinate2D)coord{
coordinate = coord;
return self;
}
the "retain" is normally used for the setter, isn't it? so here, we use the setter, in initWith..., but we don't use "retain"... any idea?
Thanks
CLLocationCoordinate2D is not an Objective C object, so attempting to send retain and release to it doesn't make sense.
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
This declares an assign read only property, which is the only correct thing to do for a property with a plain C type. Additionally you have said it is nonatomic which means that there is no code to synchronize the property. Since the property is a struct consisting of two 64 bit values, that probably means that you can get an inconsistent result back if you read the property at the same time as some other thread is changing it.
the "retain" is normally used for the setter, isn't it? so here, we use the setter, in initWith...
No, you don't actually. The line
coordinate = coord;
actually assigns the instance variable directly. However, this is what you want in this case. If the property was not read/write and was an Objective-C object type, it would still be assigning the instance variable directly. In that case, you'd need one of the following.
[self setCoordinate: coord];
or
self.coordinate = coord;
or
coordinate = [coord retain]; // in init only
By the way, your init is wrong. It should follow the pattern:
-(id)initWithCoordinate:(CLLocationCoordinate2D)coord{
self = [super init]; // assuming init is the designated initialiser of the super class
if (self != nil)
{
coordinate = coord;
}
return self;
}
In your specific case, readonly means that you class allocates the object and then gives access to it through a property that does not allow this property to be changed from outside.
In general, the object will be nevertheless retained by the class when it allocates it, and released when dealloc is executed.
In your case, the object of type CLLocationCoordinate2D is copied when assigning to the ivar:
coordinate = coord;
because it is not a pointer object, rather a simple struct made out of 2 doubles:
typedef double CLLocationDegrees;
typedef struct {
CLLocationDegrees latitude;
CLLocationDegrees longitude;
} CLLocationCoordinate2D;
So, that is the reason why you don't see any retain in the code. If instead of being a CLLocationCoordinate2D object, it had been an NSString you would have probably needed a retain when doing the assignment to the ivar. (I say "probably" because it all depends on the ownership of the assigned object).
The retain property is used for objects that need to be (surprise) retained. That is: your objects needs the object assigned to the property to stay around, it may not be deallocated.
In your case, it wouldn't change anything as a struct, not an object.
But what you're using in the cited code is readonly, and that means there is no setter, only a getter.

Objective-C Property - Difference Between Retain and Assign

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.