Prazi
Prazi

Reputation: 335

@property retain - iPhone

I am newbie to iPhone programming. I have the following doubt which is stopping me to go ahead. Please consider the following code:

---------.h------
@interface myClass: UIViewController
{
    UIImage *temp;
}

@property (nonatomic, retain) UIImage *temp;

 ---------.m------
 @interface myClass
 @synthesize temp;

 -(void) dealloc
 {
   [temp release];
   [super dealloc];
 } 
  1. The above is the only program code. Thats it ... nothing else. Do I need to declare [temp release] in dealloc method even though I am not using the property accessor method in my program at all. What if I don't declare [temp release] in dealloc. Will that create memory leak as I am releasing something which I haven't retained as I am not calling property accessor method.

  2. Also when i print retain count for temp why does it show 0 even though it is getting retained in @property.

Thanks in advance

Upvotes: 3

Views: 1416

Answers (3)

Bill Garrison
Bill Garrison

Reputation: 2049

Your code is correct.

The general rule is that, for all variables you declare in @interface, you must clean them up in -dealloc. Some variables will need to be released, others just need to be nil'd out, depending on how you've declared the @property.

In your example above, temp may never have been given a value explicitly by you, but the ObjC runtime will have initialized the value of temp to nil when an instance of your class gets allocated.

Sending a -release to a nil object is generally not a problem, so the [temp release] is fine. It's a no-op. When temp has a non-nil value in -dealloc, the [temp release] gets to do its job of freeing up the memory.

If you need temp to have a non-nil value on creation, you'll need to implement the -init method and make sure it gets some value. While your class is legitimate & functional without an -init method, you really should get in the habit including one in every custom class you design.

You'll need the default initializer at a minimum: -init. You may also want to design a more detailed initializer that could be used to give your temp ivar an a value, like -initWithImage:

Here's what you should also be including in your class:

@implementation MyClass

...

- (id) init {
   self = [super init];
   if (self != nil) {
      // The minimal default initializer.
      // temp will already have a value of nil, so you don't need necessarily 
      // need to do anything more, unless temp needs a real value on initialization.
   }
   return self;
}

- (void) dealloc {
...
}

@end


To implement a more detailed initializer, which would be known as the designated initializer, you would to something like this:

@implementation MyClass

...

- (id) initWithImage:(UIImage *)newImage {
   self = [super init];
   if (self != nil) {
      temp = [newImage retain];
   }
   return self;
}

// Implement the default initializer using your more detailed initializer.

- (id) init {
   // In this default initializer, every new instance comes with a temp image!
   return [self initWithImage:[UIImage imageNamed:@"foobar"]];
}

- (void) dealloc {
...
}
@end

Here, the designated initializer -initWithImage: is the authoritative initializer. All other initializers, including -init, get implemented using -initWithImage:.

You get to exercise a lot of discretion over whether to implement any initializers beyond the minimal default initializer. Maybe -init is good enough for your purposes. That's fine. Sometimes more detailed initializers make using the class more convenient. Experience (and the Force) will be your guide.

Note that I didn't use the generated property accessor in either initializer method. If you aren't required by circumstances, you should generally avoid using property accessors in -init methods and -dealloc, primarily because of potential pain-in-the-ass issues with side effects of automatic key-value coding notifications.

The initializer and dealloc methods play a special role in a class. As the class designer, it is your responsibility to set and clean up instance variables in these methods. A good rule of thumb is to leave the use of synthesized property accessors for the callers of your class, and the implementation of other methods in the class.

When doing initialization of an instance, or deallocation, you can and should touch the ivars directly. They're yours. You declared them, so you can handle them directly. When implementing other methods in your class, you generally should use the property accessors.

JeremyP's link to the Cocoa Conceptual documentation on objects is a good one. You should definitely read the sections on Objects, and periodically re-read it as you gain more experience writing custom classes of your own. Eventually, it will all start making sense.

Upvotes: 0

vicvicvic
vicvicvic

Reputation: 6234

  1. If no value has ever been assigned to (an instance of) myClass.temp, then there won't be a leak. But you should release it in your dealloc.

  2. @property is only a declaration that instance of myClass will have this property. You need to assign it a value before that value gets retained.

    myClass *instance = [[myClass alloc] init];
    
    // instance will now retain the value passed in
    // and is therefore responsible for releasing it
    instance.temp = [UIImage imageNamed:@"whatever"];
    
    // if instance is not retained anywhere else,
    // its dealloc will be called
    [instance release];
    

On a sidenote, you should give your classes names that start with an uppercase letter, i.e. MyClass. Not required, but makes things clearer.

You can also use self.temp = nil; in your dealloc You're sorta not supposed but it kinda works better and looks cleaner. It's a bit of an iffy subject...

Upvotes: 1

NSAlexC
NSAlexC

Reputation: 395

What you are doing is correct. Scroll to the "dealloc" section of this Apple Doc: Declared Properties

Soon, however, these properties will be cleaned up automatically when you synthesize them (in the next Cocoa update) -- that being said, a convention I have personally began to follow so that my code works in the future is setting self.temp = nil; in dealloc instead of sending a release message (read the apple doc i posted, it explains this). The accessor method created at runtime releases the object first, so for me and quite a few other devs, this is a better/safer way of cleaning up declared properties in our dealloc.

Upvotes: 0

Related Questions