views:

93

answers:

1

Hi

I have noticed that the memory usage of a program I wrote, keep increasing over time. XCode's instruments shows no memory leak, yet you can see the heap stack growing over time..

Upon investigation, a lot of the memory usage come from the IBOutlet UI objects. The interface is build with Interface Builder.

Typical usage would be like:

header:

@interface HelpViewController : UIViewController <UIWebViewDelegate> {
    IBOutlet UIWebView    *webView;
    IBOutlet UIBarItem    *backButton;
    IBOutlet UIBarItem    *forwardButton;
    NSString    *URL;
    IBOutlet UIActivityIndicatorView *spin;
}

@property (nonatomic, retain) NSString *URL;

And for the usage :

- (void)webViewDidStartLoad:(UIWebView *)mwebView {
    backButton.enabled = (webView.canGoBack);
    forwardButton.enabled = (webView.canGoForward);
    [spin startAnimating];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    backButton.enabled = (webView.canGoBack);
    forwardButton.enabled = (webView.canGoForward);
    [spin stopAnimating];
}

Looking at the heap stack, you find that the UIActivityIndicatorView *spin object isn't properly deallocated, and its memory footprint will keep growing.

However, if I change the code to: header:

@interface HelpViewController : UIViewController <UIWebViewDelegate> {
    IBOutlet UIWebView    *webView;
    IBOutlet UIBarItem    *backButton;
    IBOutlet UIBarItem    *forwardButton;
    NSString    *URL;
    UIActivityIndicatorView *spin;
}

@property (nonatomic, retain) NSString *URL;
@property (nonatomic, assign) IBOutlet UIActivityIndicatorView *spin;

And in the code I do:

synthesize spin;

- (void)webViewDidStartLoad:(UIWebView *)mwebView {
    backButton.enabled = (webView.canGoBack);
    forwardButton.enabled = (webView.canGoForward);
    [self.spin startAnimating];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    backButton.enabled = (webView.canGoBack);
    forwardButton.enabled = (webView.canGoForward);
    [self.spin stopAnimating];
}

Nothing more, nothing else, then the heap stack doesn't grow anywhere as much.. and the UIActivityIndicatorView object doesn't leave any stuff behind

I can't figure out why it would make a difference here having an assign property or not, it just doesn't make sense ! Unless I massively misunderstood what's happening.

Any explanations would be welcomed..

Thanks

+3  A: 

You need to release the objects in the dealloc method:



 -(void)dealloc {
   [webView release];
   [backButton release];
   [forwardButton release];
   [URL release];
   [spin release];
   [super dealloc];
}

The reason why the problem doesn't occour in your second version is, that you set the property with the attribute assign, usually you should use retain for "object-properties" assign is usually used for the basic datatypes like int, float, bool etc...

EDIT:

to the part with retain and assign, afaik the behaviour is the following: If the property is made with assign, then setting


self.thatVariable = something;

would be the same as:


thatVariable = something;

if you used retain it would be the same as:


[thatVariable release];
thatVariable = [something retain];

So if you used assign for variables that hold pointers to objects you can't be sure, that your object isnt deallocated somewhere else, which would result in a bad access.

Afaik the only reason to use assign with object is to get a weak reference. If you have to object which would both retain each other, none of it would ever get released. so thats a spot where you would use assign for objects. (f.e. often in the delegate-pattern. the object would retain it's delegate and the delegate would retain the object. In this case the delegate is often assigned)

Tobi
I think that it is recommended to use 'self.webView = nil;' instead of '[webView release]' in your dealloc or viewDidUnload method. This does the right thing whether you use release or assign in your @property statement. (Just don't forget the self. part, that would be very bad.)
BP
In dealloc you should always use [webView release] instead of self.webView=nil, to avoid the clearing triggering any KVC observers or having any other side effect.
Kendall Helmstetter Gelner
Sorry, but this doesn't explain why there would be a difference between the assign attribute and no attribute at all.Both cases should trigger increased memory usage.By the way, if using the assign property, doing a release in dealloc will trigger a segmentation fault. If you do a release in dealloc, you need to use the retain property instead
jyavenard
Oh sorry youre right, i didnt get that in the first place. usually no property should result in an assign... I'm sorry I misunderstood your problem. in this case i have no idea :( sry
Tobi