简体   繁体   中英

iPhone memory management

I am newbie to iPhone programming. I am not using Interface Builder in my programming. I have some doubt about memory management, @property topics in iPhone. Consider the following code

@interface LoadFlag : UIViewController {
  UIImage *flag;
  UIImageView *preview;

}

@property (nonatomic, retain) UIImageView *preview;
@property (nonatomic, retain) UIImage *flag; 

...   

@implementation LoadFlag
@synthesize preview;
@synthesize flag;

- (void)viewDidLoad
{
  flag = [UIImage imageNamed:@"myImage.png"]];
  NSLog(@"Preview: %d\n",[preview retainCount]); //Count: 0 but shouldn't it be 1 as I am retaining it in @property in interface file
  preview=[[UIImageView alloc]init];
  NSLog(@"Count: %d\n",[preview retainCount]); //Count: 1 
  preview.frame=CGRectMake(0.0f, 0.0f, 100.0f, 100.0f);
  preview.image = flag; 
  [self.view addSubview:preview];
  NSLog(@"Count: %d\n",[preview retainCount]); //Count: 2
  [preview release];
  NSLog(@"Count: %d\n",[preview retainCount]); //Count: 1
}

...
  1. When & Why(what is the need) do I have to set @property with retain (in above case for UIImage & UIImageView ) ? I saw this statement in many sample programs but didn't understood the need of it.

  2. When I declare @property (nonatomic, retain) UIImageView *preview; statement the retain Count is 0. Why doesn't it increase by 1 inspite of retaining it in @property.

  3. Also when I declare [self.view addSubview:preview]; then retain Count increments by 1 again. In this case does the "Autorelease pool" releases for us later or we have to take care of releasing it. I am not sure but I think that the Autorelease should handle it as we didn't explicitly retained it so why should we worry of releasing it.

  4. Now, after the [preview release]; statement my count is 1. Now I don't need UIImageView anymore in my program so when and where should I release it so that the count becomes 0 and the memory gets deallocated. Again, I am not sure but I think that the Autorelease should handle it as we didn't explicitly retained it so why should we worry of releasing it. What will happen if I release it in -(void) dealloc method

  5. In the statement -> flag = [UIImage imageNamed:@"myImage.png"]]; I haven't allocated any memory to flag but how can I still use it in my program. In this case if I do not allocate memory then who allocates & deallocates memory to it or is the "flag" just a reference pointing to -> [UIImage imageNamed:@"myImage.png"]]; . If it is a reference only then do i need to release it.

You say...

I am newbie to iPhone programming. I am not using Interface Builder in my programming.

Wait. What? Why not? Not using IB as someone new to the environment is generally an indication that you are doing your app the hard way. Not using IB for app development is reserved for rare, generally fairly advanced, situations.

When you write

 flag = [UIImage imageNamed:@"myImage.png"]];

you are assigning to the instance variable directly, bypassing the property accessor. Instead you need to use the dot-notation:

 self.flag = [UIImage imageNamed:@"myImage.png"]];

That explains your retain count problem.

I found it useful to declare the instance variables with a different name, like _flag for a property flag . Associate the two by writing

@property .... flag = _flag;

That way you will not accidentally use the variable directly. You can, of course, still do so if the need arises.

Question 1

This means that the synthesized property accessor messages will include an automatic retain when the message is called (but ONLY when the message is called, see next).

Question 2

This is because you are not using the property accessor message, you are just assigning to the member variable. If you use:

self.preview = [[[UIImageView alloc] init] autorelease];

The resulting retain count will be one (+1 for the init, -1 for the autorelease, +1 for the retain on the message).

NB

You will get the same retain count (one) if you do this:

preview = [[UIImageView alloc] init];

(+1 for the init, not using the property accessor message so no extra retain). Up to you which way you go with.

Question 3

The addSubview will increment the retain count again because the preview will be stored in a collection which will retain it's objects.

So yes, Basically if you are handing an object off to another object to manage (as is the case with addSubview) you can set it to autorelease and it will be released by the other object. However, since you are storing the UIImageVIew in a retained property, you will need to release it yourself (see next).

Question 4

Because you are keeping the preview object as retained property, you will need to release it in your dealloc message. So in my Question 2 example, you allocate the object, autorelease it, but assign it to retained property, so the retain count after all that will be one, you are adding it to a collection which will also retain it. When the view is cleaned up the collection will decrement the retain count, but you will need to call release as well, because you stored it in a retained property. So in your dealloc:

[preview release];

Question 5

imageNamed is a helper message that does the allocation, initialization and autorelease. So basically it is equivalent to saying.

NSData * dataForImage = get data from the myImage.png here ...
self.flag = [[[UIImage alloc] initWithData:dataForImage] autorelease];

You are storing it in a retained property (because I use self.flag in the above example), so you will need to release it in the dealloc message.

  1. You use retain to claim ownership of an object. This essentially means that when something is assigned to the property, you ensure that it's there for as long as the owning object needs it.

  2. @property ... is a statement of your the interface of your class. It doesn't mean there is a value for the property in question, only that "Instances of LoadClass have a flag property which is retained by it". Not until you actually assign values to the properties of an instance will things be retained.

  3. This is because UIView claims ownership of its subviews.

  4. Your object might not need it, but UIView still needs it.

  5. It's autoreleased by UIImage.

You should read the full guide on Memory Management by Apple. I try to think of memory management as owning objects or not... it helps.

Question 2: The @property statement in your @interface is really just a directive to the compiler to automatically generate accessor methods for an instance variable that have the characteristics you specify. @property doesn't cause any actions to happen when you run your code. The compiler will look at the @property line and generate invisible accessor code for you.

@property (nonatomic, retain) UIImageView *preview;

would cause the compiler to generate accessor methods that look something like this:

- (void) setPreview:(UIImageView *)newValue {
   [self willChangeValueForKey:@"preview"];
   if (preview != newValue) {
     [preview release];
     preview = [newValue retain];
   }
   [self didChangeValueForKey:@"preview"];
}

- (UIImageView *) preview {
   return preview;
}

@property is a timesaver for you; it directs the compiler to generate accessor code for your variables that are efficient but invisible. If you didn't use @property, you'd have to write accessor methods similar to the above in your custom class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM