Methods from #synthesize? - objective-c

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.

Related

Should I dealloc a nonnull property; and if so, how?

I'm exposing a few properties from an Objective-C project to Swift (based on this repo), but have no experience in Objective-C, so I'm rather out of my depth here, so please bear with me.
I'm wondering how to correctly dealloc a nonnull property (or whether it's necessary at all!). I've provisionally dealloc'ed the nonnull property surface by setting it to null (in the same manner as is done for the nullable partOfSpeech). However, this prompts the following warning:
Null passed to a callee that requires a non-null argument
... so I wonder whether it's redundant. Is there anything I should do instead to handle my nonnull property, during the Node class's dealloc block?
Given the interface, node.h:
#interface Node : NSObject {
NSString *surface;
NSString *partOfSpeech;
}
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
- (nullable NSString *)partOfSpeech;
#end
... And the implementation, node.m:
#implementation Node
#synthesize surface;
#synthesize partOfSpeech;
// surface is assumed to be set post-initialisation.
- (void)setPartOfSpeech:(NSString *)value {
if (partOfSpeech) [partOfSpeech release];
partOfSpeech = value ? [value retain] : nil;
}
- (NSString *)partOfSpeech {
if (!features || [features count] < 1) return nil;
return [features objectAtIndex:0];
}
- (void)dealloc {
// WARNING: "Null passed to a callee that requires a non-null argument"
self.surface = nil;
self.partOfSpeech = nil;
[super dealloc];
}
#end
... And given that a Node's lifecycle is like this:
Node *newNode = [Node new];
newNode.surface = [[[NSString alloc] initWithBytes:node->surface length:node->length encoding:NSUTF8StringEncoding] autorelease];
// ... Do stuff with newNode (eg. add to array of Node)...
[newNode release];
First: The compiler can automatically synthesize instance variables and
setters/getters for your properties. So your interface should be just
// Node.h
#interface Node : NSObject
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
#end
and no #synthesize statements are needed in the implementation file.
The compiler will automatically create instance variables
_surface and _partOfSpeech, and also create accessor methods
- (NSString *) surface;
- (void)setSurface:(NSString *)value;
- (NSString *)partOfSpeech;
- (void)setPartOfSpeech:(NSString *)value;
which do "the right thing", with or without ARC. You can override
those methods if you want to implement some custom logic, but you don't have to implement a standard setter like your setPartOfSpeech.
If you use ARC (automatic reference counting) then that is all,
nothing more is needed. And
I would really recommend to do so. The compiler inserts the required retain/release calls at compile time, and is quite clever in avoiding
unnecessary calls. See for example
Confirmed: Objective-C ARC is slow. Don’t use it! (sarcasm off)
about some comparisons. With MRC (manual reference counting), your code might even be slower, or
have memory leaks.
But to answer your question: With MRC you have to release the
instance variables in dealloc
- (void)dealloc {
[_surface release];
[_partOfSpeech release];
[super dealloc];
}
as explained in Memory Management Policy in the "Advanced Memory Management Programming Guide".
You should not use the accessor methods in dealloc as in your
self.surface = nil;
self.partOfSpeech = nil;
see Don’t Use Accessor Methods in Initializer Methods and dealloc.
If you are using manual memory management you can just release the object stored in the properties backing variable. As you've named the backing variable the same as the property use the -> to clearly reference the backing variable:
[self->surface release];
Or if you want to do this with assignment just assign the empty string literal:
self.surface = #"";
The string literal is created at compile time, lives throughout the program execution, and takes up very little space. The assignment will caused the release (and deallocation if the reference count reaches zero) of the previous value in the property, just like assigning nil (or any other value).
HTH

Releasing synthesized properties in objective C

I'm a little confused about synthesized properties. I have an array that I want to be accessible from other classes so this is my code:
MyClass.h
#interface MyClass : CCLayer {
NSMutableArray *myArray;
}
#property (nonatomic, retain) NSMutableArray *myArray;
MyClass.m
#synthesize myArray;
-(id)init
{
myArray = [[NSMutableArray alloc] init];
}
-(void)dealloc
{
[myArray release];
myArray = nil;
}
I am a little confused now..is myArray the same as self.myArray? Do I have to release self.myArray as well? Thanks.
You declared your property as retain, it means that it will be retained automatically if you will set is using self.myArray. So, you can simply create autoreleased array in your init method and set it as
myArray = [NSMutableArray array];
self.myArray = myArray;
in this case you are not have to release it in the dealloc method or anything else. And as dasblinkenlight said you have to use #synthesize if you want to be sure that self.myArray is linked with your myArray instance.
Assuming that your #synthesize directive looks like this
#synthesize myArray;
you do not need to do anything in addition to what you are already doing: your property stores its value in the instance variable of the same name.
EDITED : Removed the alternative that suggests setting self.myArray in the dealloc method.
Yes you do, the best method is to set the property nil and release your variable.
-(void)dealloc{
self.myArray = nil;
[myArray release];
[super dealloc];
}
The code you provided is not really correct.
No, accessing a property and accessing the field itself are not the same.
My guess is that you are looking at old obj C examples where it was necessary to create the field with the property.
You also have no #synthesize directive in your code.
In current obj C code there is no need to declare a field to back the property, the field and the getter and setter will be autosynthesized (generated by the compiler) for you.
The default field generation is the name of your property with an underscore in front of it.
When you access the field directly via _myArray you will bypass any retain or release code that is contained in the generated getter/setter and have to manually manage memory in a non ARC project.
So to sum up, you dont need your field definition, and you dont need a synthesize directive.
You access your field directly with _myArray, or the property via self.myArray
They are not the same thing, one goes through generated code which obeys your property definition as to retain, assign, copy and accessing the field directly bypasses these semantics altogether.
If you define your property as retain you will need to release it in dealloc
You can use either
self.myArray = nil;
which will handle the release or
[_myArray release];
_myArray = nil;
Although someone in a previous post said setting the property to nil in dealloc might cause a problem Ive never seen it actually happen in my apps, ymmv
To answer your questions:
I am a little confused now..is myArray the same as self.myArray?
Yes, but no. Both point to the same object, the same area in memory. If you read myArray or self.myArray, they're identical in behavior minus the message send overhead for self.myArray.
However if you assign to myArray, the object will not be retained. It will only be retained if you assign to self.myArray.
Do I have to release self.myArray as well?
No.
You can also choose to either release or set the property to nil. As long as the property is #synthesize'd both examples do the same thing:
-(void) dealloc
{
[super dealloc];
[myArray release];
}
-(void) dealloc
{
[super dealloc];
self.myArray = nil;
}
See here for a discussion of the pros/cons to each approach.
From the question I think you're the developer who should really be using ARC. You'll have less to learn and fewer technical problems down the road. I can't understate how important using ARC is in these days, specifically if you don't have much ObjC experience. Read this how to enable ARC for cocos2d or just use Kobold2D to be able to work with an ARC-enabled cocos2d out of the box.

How to retain my own objects and properties

I'm not sure I understood how alloc and retain work.
Recently I discovered that the NSString properties were not retained and I had to add [myString copy] when I set them. Which makes me wonder if I misunderstood the whole way of using retain/alloc
Please, may someone tell me if I'm doing it correctly? I read a lot and had a look on open source projects, this let me thing that I may have been wrong since the beginning.
Here is my way of doing it:
/**** VIEW.h *****/
#import "MyClass.h"
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
#property (nonatomic, retain) MyClass *myObject;
- (void)defineObject;
#end
.
/**** VIEW.m *****/
#import "VIEW.h"
#implementation MyViewController
#dynamic myObject;
- (void)viewDidLoad
{
[super viewDidLoad];
[self defineObject];
NSLog(#"My object's name is: %#", myObject.name);
}
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
.
/**** MyClass.h *****/
#interface MyClass : NSObject {
//not sure if this line is still necessary
NSString *name;
}
#property (nonatomic, retain) NSString *name;
- (id)initPersonalised;
- (void)setName:(NSString *)name;
- (NSString *)name;
#end
.
/**** MyClass.m *****/
#import "MyClass.h"
#implementation MyClass
#dynamic name;
(id)initPersonalised{
self = [super init];
name = #"Undefined";
}
- (void)setName:(NSString *)name{
self.name = [name copy];
}
- (NSString *)name{
return [self.name copy];
}
#end
I hope you can bring a bit of light, after months of programming this way, I'm less and less sure of doing it well.
This is indeed a topic that every Objective C programmer stumbles upon. There are a few things one needs to know:
Instance variable vs. property access
Within MyViewController,
myObject = xxx;
and
self.myObject = xxx;
are two different things. The first directly assigns to the instance variable and does neither release to old referenced insance nor retain the newly assigned instance. The latter one uses the property setter and thus releases the old and retains the new value.
Deallocation
Even when you have declared an implemented a property that takes care of retaining and releases the values, it won't take care of deallocation when your object (MyViewController in your case) is released. So you must explicitly release it in dealloc:
-(void) dealloc {
[myObject release];
[super dealloc];
}
Now to your code:
The snippet:
myObject = [[MyClass alloc] initPersonalised];
is perfectly okay. When you create an object, you use the pair of alloc and initXXX. The always create an instance with the reference count set to 1. So by directly assigning it to the instance variable, you create a clean constellation. I don't see no other way of creating the instance.
In MyClass you could use #synthesize name instead of #dynamic. Then the compiler would implement name and setName: automatically and you wouldn't need to do it yourself.
Finally, your missing dealloc.
Update:
If you use:
self.myObject = [[MyClass alloc] initPersonalised];
then you have a memory leak because initPesonalised sets the reference count to 1 and the setter of myObject increases it to two. If you want to use the setter, then I has to be:
MyClass* mo = [[MyClass alloc] initPersonalised];
self.myObject = [[MyClass alloc] initPersonalised];
[mo release];
It would be different if you weren't using initXXX to create a new instance. The class NSString for example has many methods called stringXXX, which create a new instance (or return a shared one) that has (conceptually) a reference count of 1 that will later automatically decreased by one. Then you better use the setter:
self.name = [NSString stringWithFormat: #"instance %d", cnt];
If you want to use copy instead of retain for your string property (which is good practice), then you can simply declare your property like this:
#property (nonatomic, copy) NSString *name;
When you then use #synthesize to implement the getter and setter, the compiler will generate them using copy instead of retain.
And NSString *name; is necessary even if you use #property and/or #synthesize to implement the property.
Alloc and init are methods that always go hand-in-hand. alloc allocates space for your object, and init initializes your object to some value. When you call alloc, you are responsible for freeing that object later. If you call copy, you are also responsible for releasing that object later. It's considered good practice to always initialize your objects right after you allocate them.
Now, to answer the questions I found in your code.
#interface MyViewController : UIViewController {
//Is the following line really necessary?
MyClass *myObject;
}
So is that line necessary? That depends. Does it make sense that your object has a MyClass as a property? This is a question only you can answer based on your design. I recommend you to study Object-Oriented Programming in more depth.
- (void)defineObject
{
//Here particularly, Why doesn't it work without both alloc and init
//shouldn't "#property (nonatomic, retain) MyClass *myObject;" have done that already?
myObject = [[MyClass alloc] initPersonalised];
[myObject setName:#"my name"];
}
Not necessarily. You are just providing a pointer to an object of the specified kind. The moment you set your property, depending on the property modifiers, your class will know what to do with MyObject.
In that way, there's no need to call [yourObject copy]. In this way your properties will be copied instead of being retained. Just don't forget to release it later in your -dealloc method, like you would with retain properties.
All in all, this is what I recommend you to study a bit more:
Object-Oriented Programming (not related to your issue, but I can tell you are not comfortable using it. Objective-C is heavily object oriented, so you want to understand OOP).
iOS Memory Management.
You can have a look at the Memory Management Guide. It will help you to better understand the alloc & retain concepts; hope this helps you.

Is releasing memory of Objective-c 2.0 properties required?

Something I have been wondering about properties for a while. When you are using properties, do you need to override the release message to ensure the properties are released properties?
i.e. is the following (fictitious) example sufficient?
#interface MyList : NSObject {
NSString* operation;
NSString* link;
}
#property (retain) NSString* operation;
#property (retain) NSString* link;
#end
#implementation MyList
#synthesize operation,link;
#end
You should always release the backing variables in dealloc:
- (void) dealloc {
[operation release];
[link release];
[super dealloc];
}
Another way:
- (void) dealloc {
self.operation = nil;
self.link = nil;
[super dealloc];
}
That's not the preferred way of releasing the objects, but in case you're using synthesized backing variables, it's the only way to do it.
NOTE: to make it clear why this works, let's look at the synthesized implementation of the setter for link property, and what happens when it is set to nil:
- (void) setLink:(MyClass *) value {
[value retain]; // calls [nil retain], which does nothing
[link release]; // releases the backing variable (ivar)
link = value; // sets the backing variable (ivar) to nil
}
So the net effect is that it will release the ivar.
In non-GC applications, yes. It is usual to assign nil instead of releasing the ivars.
My best experience is to release ivars initialized with init and assign nil to properties with retain and copy mode.
In your case I would assign nil
- (void) dealloc {
self.operation = nil;
self.link = nil;
[super dealloc];
}
The best way to do this is:
- (void)dealloc {
[operation release], operation = nil;
[link release], link = nil;
[super dealloc];
}
It would indeed be more convenient to use the generated setter methods
self.operation = nil;
but that is frowned upon. You don't always know which thread an object is deallocated on. Thus using an accessor may cause problems by triggering KVO notifications.
The catch here is that you need to adapt your dealloc to match the object management policy defined in your #property. E.g. don't go releasing a iVar backing an (assign) property.
No, you override the -dealloc method. And yes, if you don't release your properties (or rather, the backing ivars), you will leak. So in your #implementation here you should have something like
- (void)dealloc {
[operation release];
[link release];
[super dealloc];
}
Synthesizing a property only creates getter and setter methods, and therefor won't release the ivar when the object is deallocated. You need to release the ivar yourself.
In pre-ARC whenever you see new, alloc, retain and copy, whether it is an instance var or a property you must release. In ARC whenever you have a strong variable you must set it to nil.
In either case you have to override dealloc().

Should I release this property?

I'm a objective c newbie, and i'm having a bit of problems with memory management, I've read the apple's memory management policies, however i need a bit of clarification here, this is pretty simple i guess, but i would like to ask you if I'm right:
Given this property:
#interface Test : NSObject {
NSArray *property1;
}
#property (nonatomic,retain) NSArray* property1;
#end
...
//And its implementation:
#implementation Test
#synthetize property1;
-(id) init {
if (self=[super init]) {
self.property1=[[[NSArray alloc] initWithCapacity:5] autorelease];
}
return self;
}
-(void) dealloc {
[super dealloc];
[property1 release];
}
#end
Is it right to issue an Autorelease message to the allocated object in the init method?, i do this cause in apple's document, says that every allocated object should be released by the developer, then, I think, alloc sets retain count to 1, then the property (nonatomic, retain) adds 1, so retain==2, then autorelease substracts 1, and when the dealloc method is called, property1 is released and retain count==0, am I right?
You have your memory management right, though Apple (and a lot of other people) generally recommend not using accessors in your initialization methods because accessors can have side effects beyond simply setting an instance variable that your class might not be set up to handle yet. And in that case, you wouldn't want to autorelease since you'd want ownership of the object.
one side note: in your dealloc, you need to release the property before calling [super dealloc], because [super dealloc] eventually deallocates the memory of the object, which includes the memory containing the property1 variable, so it is invalid to refer to that variable after you call [super dealloc]. It should be:
-(void) dealloc {
[property1 release];
[super dealloc];
}
One of the nice things about using properties is that you can encapsulate all of your "releasing" behavior regardless of whether your property is set to retain, copy, assign, or whatever by just doing this:
self.property1 = nil;
Personally I've gotten in the habit of setting all properties to nil (using self.property, not just accessing the member variable directly) in dealloc so that even if I change how the memory management works for the member variable it works correctly.