Property attribute "retain" doesn't seem to be working? - objective-c

I've implemented a bit of code from one of the many Apple code examples, but I'm having a bit of trouble, because the retain attribute of one of the properties doesn't appear to be working. Here's the property declaration:
#property (nonatomic, retain) EditingViewController *editingViewController;
And here's the code:
- (EditingViewController *)editingViewController {
// Instantiate the editing view controller if necessary.
if (editingViewController == nil) {
EditingViewController *aController = [[EditingViewController alloc] init];
editingViewController = aController;
[aController release];
}
return editingViewController;
}
I understand that (retain) is supposed to cause the retain count to increase by 1 on assignment; however, the code fails unless I do send [aController retain] myself, or don't send [aController release]. What am I missing here?

When you reference editingViewController, it is equivalent to self->editingViewController, i.e. an access to an ivar.
If you want to use a getter or setter, you need to use self.editingViewController, or equivalently [self setEditingViewController:aController].
This is why I prefer to use an ivar with a different name to the property, for example:
EditingViewController* i_editingViewController;
#property (nonatomic, retain) EditingViewController *editingViewController;
#synthesize editingViewController = i_editingViewController;
Then you can write your lazy getter as:
- (EditingViewController *)editingViewController {
// Instantiate the editing view controller if necessary.
if (i_editingViewController == nil) {
i_editingViewController = [[EditingViewController alloc] init];
}
return i_editingViewController;
}
or
- (EditingViewController *)editingViewController {
// Instantiate the editing view controller if necessary.
if (i_editingViewController == nil) {
EditingViewController *aController = [[EditingViewController alloc] init];
self.editingViewController = aController;
[aController release];
}
return i_editingViewController;
}
I would probably use the former method (not invoking the setter) because the value of editingViewController (as seen by any observer) has not really changed, but either way should work fine and the different name (for ivar and property) help avoid the confusion or accidental misused. It is also a mild encouragement to use the property (since it avoids the slightly ugly prefix).
Note that Apple reserves the _ prefix, and that setters and getters should not be used in the init/dealloc routines.

You have to write self.editingViewController in order to use the property. Just "editingViewController" is a direct access to the Class member variable, whereas self.editingViewController is equivalent to [self setEditingViewController:...] and will do the appropriate retain/release job.

Related

Why does initWithCoder need self.property?

I tend to regularly use self.property in my Objective C code when accessing variables as I understand that this makes use of the getter/setter methods (either explicitly coded or automatically generated).
Another coder told me recently that it's best to use _property instead, throughout the code. But my understanding is that _property is really only for use in init and dealloc methods.
Today I found a bug in some code that uses initWithCoder. I was using _property in the initWithCoder method and had to change it to self.property. This was when setting an NSData object. Here is the original code:
#property (nonatomic, strong) NSData *data;
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
_data = [decoder decodeObjectForKey:#"data"];
return self;
}
And I had to change it to this, to get it to work:
#property (nonatomic, strong) NSData *data;
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
self.data = [decoder decodeObjectForKey:#"data"];
return self;
}
My question is - why is initWithCoder the exception here? If it's generally accepted that it's best to use _property in an init method, then why is initWithCoder different?
It seems now like the general rule is:
Use self.property except in init/dealloc methods, where _property should be used (except in initWithCoder, where self.property should be used).
Is this correct?
I do not think it is generally true that you must use properties in initWithCoder:. I have a lot of code (and have seen a lot) where ivar access is used in initWithCoder:, if that may help as a hint.
If you were not using ARC, then your implementation setting _data would have a problem in that the object would be soon autorelased. But under ARC your code is correct.
So, I tend to think that something different was causing the issue in your case. As an example, if you use KVO, then you should use properties, otherwise the KVO-related notifications are not generated. You should provide more information as to what exactly led you to think that the assignment to _data was the cause of the issue, and about the visible effect of that issue in other parts of your code.

How to properly manage id instance variable assign then retain

I have a class that has a property:
#property (nonatomic, assign) id customDatePicker
Based upon user choice I will need a UIDatePicker or a UIPicker so I typecast the ivar and retain it and subsequently dealloc it. Is this the correct way to manage the property's memory?
// init snippet
if (useUIDatePicker) {
customDatePicker = (UIDatePicker *)[[[UIDatePicker alloc] initWithFrame:frame] retain];
} else {
customDatePicker = (UIPickerView *)[[[UIPickerView alloc] initWithFrame:frame] retain];
}
- (void)dealloc {
[customDatePicker release];
[super dealloc];
}
No.
When you declare the property as assign, you should not be retaining the object. The assign option is used for non-object variables and for situations where having a retained property would create a cycle, with both objects retaining each other. Declaring a property as assign means you will not be managing the memory of the object; you should neither call retain nor release on it.
You are also over-retaining the picker object. Retaining an object creates a claim on the object; you don't want it to disappear until you say you are done with it. You relinquish a claim, allowing an object to be deleted, by calling release. When you call alloc, that creates the same kind of claim as calling retain. So this line:
[[[UIDatePicker alloc] initWithFrame:frame] retain];
creates two claims, one for alloc and one for retain. Later, you only call release once, which means that you will always still have one claim on this object, and it will have turned into a memory leak.
What you should do is:
#property (nonatomic, retain) id customDatePicker
if (useUIDatePicker) {
customDatePicker = [[UIDatePicker alloc] initWithFrame:frame];
} else {
customDatePicker = [[UIPickerView alloc] initWithFrame:frame];
}
Now you have only one claim on the picker because you used alloc.
(You don't need to cast the assignment; when you are assign to a generic pointer you can use any kind of object.)
Also take a look at the Apple Memory Management docs.

I wonder about releasing variables

UIView *view; //1
UISegmentedControl *scopeBar; //2
NSMutableArray *array; //3
#property (nonatomic, retain) IBOutlet UIView *view;
#property (nonatomic, retain) UISegmentedControl *scopeBar;
#property (nonatomic, retain) NSMutableArray *array;
.m
#synthesize view, scopeBar, array;
for (id subView in [view subviews]) {
if ([subView isMemberOfClass:[UISegmentedControl class]]) {
scopeBar = (UISegmentedControl *)subView;
}
}
array = [[NSMutableArray alloc] init];
- (void)dealloc {
}
I think that only the third of the variables has to be released in the dealloc method.
Is that right?
Yes, (array needs to be released) because you alloc it. So, it's programmer's responsibility to release it. So -
- (void)dealloc {
[ array release ] ;
// Any other resources alloc, init, new should be released
}
For more info on what to release, Memory management - ObjectiveC
And I think you will find good suggestions in this question about your query
Why should we release?
Contrary to some of the answers, you have to release your outlet (view) as well, and not only in the dealloc but also in the viewDidUnload, the easiest way is to set it to nil :
self.view = nil;
Also note that if you don't access your properties but your instance variables (i.e. without self. prefix) your retain attribute won't help you and you are not retaining the object. That means that as soon as scopeBar would be removed out of the subViews of the view, it will be released and you end up accessing a zombie.
As a rule of thumb, it's best to use the properties accessor everywhere except in the init methods so that you don't have to deal with the memory management explicitly. Setting them to nil in the dealloc and viewDidUnload in case of outlets should be enough then.
Also, don't do what Jenifer suggested and once you've called a release on a variable, don't set the property to nil, that would overrelease it.
I think that only the third of the variables has to be released in the dealloc method. Is that right?
// no. your dealloc should look like this:
- (void)dealloc {
// note: *not* using accessors in dealloc
[view release], view = nil;
[scopeBar release], scopeBar = nil;
[array release], array = nil;
[super dealloc];
}
// your assignment of `scopeBar` should look like this:
...
self.scopeBar = (UISegmentedControl *)subView;
...
// you want to retain the view, as advertised.
// consider avoiding an ivar if you can easily access it.
// your assignment of `view` should look like this:
...
self.view = theView;
...
// you want to retain the view, as advertised.
// consider avoiding an ivar if you can easily access it.
// your assignment of `array` should look like this in your initializer:
// note: *not* using accessors in initializer
...
// identical to `array = [[NSMutableArray alloc] init];`
array = [NSMutableArray new];
...
// and the assignment of `array` should look like this in other areas:
...
self.array = [NSMutableArray array];
...
// you're likely to be best suited to declare your array as
// follows (assuming you really need a mutable array):
...
NSMutableArray *array; // << the declaration of the ivar
...
...
// the declaration of the public accessors.
// note the array is copied, and passed/returned as NSArray
#property (nonatomic, copy) NSArray *array;
...
// finally, the implementation manual of the properties:
- (NSArray *)array {
// copy+autorelease is optional, but a good safety measure
return [[array copy] autorelease];
}
- (void)setArray:(NSArray *)arg {
NSMutableArray * cp = [arg mutableCopy];
// lock? notify?
NSMutableArray * prev = array;
array = cp;
[prev release], prev = nil;
// unlock? notify? update?
}
other answers assume that dangling pointers (e.g., you still hold a pointer to view, although the view may have changed behind your back) are allowable.
they should not be allowed in real programs. they are extremely dangerous, and it can very difficult to reproduce errors they cause. therefore, you must ensure you own a reference to the pointers you maintain/hold.
you should also use the accessors in the public interface for the subclasser's sake - in case they override them. if you don't want to allow/support that, consider simply using a private variable.
As i think you should release and set them nil because you have made them properties so do this:-
in your dealloc
[array release];
self.array=nil;
self.scopeBar=nil;
self.view=nil;

Add an objective #property attribute in objective-c

Does anyone know of a way to add additional attribute types to the #property keyword without modifying the compiler? Or can anyone think of another way to genericize getter/setter creation?
Basically, I have a lot of cases in a recent project where it's handy for objects to lazily instantiate their array properties. This is because we have "event" objects that can have a wide variety of collections as properties. Subclassing for particular events is undesirable because many properties are shared, and it would become a usability nightmare.
For example, if I had an object with an array of songs, I'd write a getter like the following:
- (NSMutableArray *)songs {
if (!songs) {
songs = [[NSMutableArray alloc] init];
}
return songs;
}
Rather than writing dozens of these getters, it would be really nice to get the behavior via...
#property (nonatomic, retain, lazyGetter) NSMutableArray *songs;
Maybe some fancy tricks via #defines or something? Other ideas?
You can always use macros. Even if you modified the compiler, you would probably still want to do this in #synthesize instead of #property, since there is no need to publish this implementation detail. And with a macro it is easy to use any init method. Unfortunately the macros are not aware of the getter= property attribute.
#define synthesizeLazyGetterWithInit(PROPERTY,TYPE,INIT)\
-(TYPE *) PROPERTY { if ( !PROPERTY ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }
#define synthesizeLazyGetter(PROPERTY,TYPE)\
synthesizeLazyGetterWithInit(PROPERTY,TYPE,init)
#implementation MyClass
synthesizeLazyGetter(songs,NSMutableArray)
synthesizeLazyGetterWithInit(other,NSMutableArray,initWithCapacity:0)
#end
Edit:
#define synthesizeLazyGetterOptional(PROPERTY,TYPE,INIT);\
-(TYPE *) PROPERTY:(BOOL)inAllocate { if ( !PROPERTY && inAllocate ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }\
-(TYPE *) PROPERTY { return [self PROPERTY:YES]; }\
-(BOOL) PROPERTY##Initialized { return nil != PROPERTY; }

Methods from #synthesize?

When you synthesize a property (see below)
#interface CelestialBody : NSObject {
NSString *name;
}
...
#interface Planet : NSObject {
NSString *name;
int mass;
CelestialBody *moon;
}
#property(nonatomic, retain) NSString *name;
#property(assign) int *mass;
#property(nonatomic, retain) CelestialBody *moon;
...
#implementation Planet
#synthesize name;
#synthesize mass;
#synthesize moon;
...
You get setters and getters for each of the iVars (i.e.)
[newPlanet setName:#"Jupiter"];
[newPlanet setMass:57];
NSString *closestName = [newPlanet name];
int largestMass = [newPlanet mass];
CelestialBody *newMoon = [[CelestialBody alloc] initWithName:#"Callisto"];
[self setMoon:newMoon];
[newMoon release];
but you also get the ability to release the object using ...
// Releases the object (frees memory) and sets the object pointer to nil.
[self setMoon: nil];
There will of course be deallocs for each Class.
// Moon
-(void)dealloc {
[name release];
[super dealloc];
}
// Planet
-(void)dealloc {
[name release];
[moon release];
[super dealloc];
}
Am I getting this right?
gary
Unless your planet object is declared as a property within some other class, using the retain/copy attributes, you can't release it this way.
When you declare a property using retain/copy, the resulting setter will release the old value and assign the new value, retaining or copying it in the process. If you pass nil, you will release the old value and assign nil, retaining or copying it, and retaining/copying nil is nil, so effectively you end up releasing the old value and assigning nil to the ivar.
This is an acceptable way to release instance variables.
In order to be able to release your newPlanet instance this way, you'd have to have declared it in a class as a property with either retain or copy.
As a further example, since your planet object declares its properties in this way, you could release those using this method.
Or in the Planet class's dealloc method, you could do:
self.name = nil;
This would release name and assign nil to it.
"you also get the ability to release the object"
Yes, as long as you didn't declare it with the assign attribute.
As you probably know, one of the reasons (although perhaps not the primary one) for using declared properties is that you can do:
self.moon = aMoon;
rather than;
[self setMoon:aMoon];
They are equivalent. That means that your deallocation can look like this:
self.moon = nil; // Releases and sets to nil
But remember to never just do:
moon = nil; // Sets to nil, doesn't release
It's very good practice to not only release the object, but to set the variable to nil, as you do, because otherwise some other code could mistakenly try to use the pointer that is left in the variable.
Your example shows the synthesis of one class's ivars (those of Planet) but the use of another (whatever "self" is). Is the "newPlanet" property of "self" in your last example also synthesized as (retain)? If so, then: Yes, setting newPlanet to nil will release whatever self's old "newPlanet" was.
I think you are not getting it right.
After your question update, yes, you can do that, and also:
self.moon = [[CelestialBody alloc] initWithName:#"Callisto"];
and release it later, probably in your dealloc method:
self.moon = nil;
Apple Objective-c 2.0 Properties and Memory Management docs are pretty good. Check Mac Dev Center library.