(iphone) basic memory management question - iphone

I have used following 2 patterns to create a view.
#property (retain, nonatomic) SomeView* someView;
...
// First pattern
self.someView = [[SomeView alloc] initWithFrame frame];
// Second pattern
SomeView* aSomeView = [[SomeView alloc] initWithFrame];
self.someView = aSomeView;
[aSomeView release];
Now, looking back at this code, the first pattern's method should be changed to
self.someView = [[[SomeView alloc] initWithFrame frame] autorelease];
shouldn't it?
I feel dumb :(

Look at it like this:
[[SomeView alloc] initWithFrame: frame];
The above line creates an object and gives it a retain count of 1.
self.someView = [[SomeView alloc] initWithFrame: frame];
This line leaves it with a retain count of two, because the someView property is declared with retain:
#property (**retain**, nonatomic) SomeView* someView;
So, doing it this way leaves your someView property pointing to an object with retain count of 2. You can do it this way if you add an autorelease call to it:
self.someView = [[[SomeView alloc] initWithFrame: frame] autorelease];
Your second pattern is better, if you ask me. You create an object with a retain count of one. You assign it to a retaining property (now it has a retain count of 2) and then you release the original variable, leaving the object again with a retain count of 1. It's three lines where you might want only one, but it makes sense in the right context. Additionally, it's usually best to avoid using autorelease outside of an alloc or copy method since its usually an indication you don't fully understand memory management in Obj-C.
And as a commenter said in the comments to the question, don't feel dumb. None of this is intuitive at first. Nobody picks up a guitar and plays like Hendrix their first time.

Yes, you are right. autorelease means "release a bit later".

Yes, I think you should change that. With self.someView = you are calling the setter which increases the retain count.

Now, looking back at this code, 1's method should be changed to self.someView = [[[SomeView alloc] initWithFrame frame] autorelease];
shouldn't it?
correct
a)
SomeView * view = [[SomeView alloc] initWithFrame:frame];
self.someView = view;
[view release], view = nil;
b)
self.someView = [[[SomeView alloc] initWithFrame:frame] autorelease];
many people prefer b, simply because it is less to type.
i prefer an approach similar to a because:
defects (such as over-releasing) are often exposed near the call site, rather than when the pool is destroyed (this often means you have to load up Instruments in Zombie mode to locate the callsite)
it performs better and minimizes memory usage (in general, but not much in this specific case)
you have more opportunity to check for invalid states and results
you have a chance to init/configure the view/object for its usage before adding it to self, which is usually preferred

Related

Xcode Instruments Leak coming from UIDeviceRGBColor

I have a leak coming from UIDeviceRGBColor. The responsible frame is +[UIColor allocWithZone:]. I am not using ARC.
The leak is coming from the method below.
- (void) lAction
{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.05;
mapRegion.span.longitudeDelta = 0.05;
[mapView setRegion:mapRegion animated: YES];
SettingsViewController *settingsViewController = [[SettingsViewController alloc]
initWithNibName:#"SettingsViewController" bundle:nil];
The leak is coming from this next line:
[self presentModalViewController: settingsViewController animated:YES];
Then the method finishes like this:
self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:40.0/255.0
green:43.0/255.0 blue:46.0/255.0 alpha:1.0];
}
Anyone know how to fix this? Thank you all!
Try:
SettingsViewController *settingsViewController = [[[SettingsViewController alloc]
initWithNibName:#"SettingsViewController" bundle:nil] autorelease];
In order to satisfy the commenter, the explanation is simply that if you're not using ARC, whenever you call alloc, the retain count of the returned object is set to 1. You are responsible for releasing it. One easy way to do that is call autorelease on it which will automatically release it at the end of the main run loop (unless you're managing your own autorelease pool, but I won't get into that). You do want to make sure that as long as you need to use an object your code has something retaining it, in this case when you call
[self presentModalViewController: settingsViewController animated:YES];
an extra retain is called on the settingViewController, so you don't have to worry about it getting dealloced when your method finishes.
I find memory management in Objective-C pretty easy, but it does require extra code and everyone uses ARC these days. If you're just making a few small changes to an existing code base, there is no need to switch to ARC, but if you're going to continue working with the code base for some time, it will be more time efficient to switch. It is pretty straightforward to do, as Xcode will do most of the work for you. (See here: http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html).

Static Analyzer showing wrong leak?? (XCode 4.0, iOS 4.3 and above)

Happy November to all,
Well I tried Xcode Build and analyze on my project, and it showed some unusual leaks, which I couldn't quite accept with my knowledge of Objective C.
So I decided to put up a test project and ask here..
MemoryTestController.h
#interface MemoryTestController : UIViewController{
UIImageView *tstImageView;
}
#property(nonatomic,retain) UIImageView *tstImageView;
#end
MemoryTestController.m
#implementation MemoryTestController
#synthesize tstImageView;
- (void)viewDidLoad{
[super viewDidLoad];
self.tstImageView = [[UIImageView alloc] //<==This object is leaking
initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
[tstImageView release];
}
-(void)dealloc{
[tstImageView release];
[super dealloc];
}
#end
When I try Build and analyze, clang static analyzer say
Potential leak of an object at line xx
And the culprit line is
self.tstImageView = [[UIImageView alloc]initWithFrame:<SomeFrame>];
I think I am releasing once for every time I am allocing/retaining. Am I missing something, or Static analyzer has some bugs?
EDIT : Is there any leak there?
Well I run the above project using Leak tool in instrument..It didn't show any leak even though I tried many times..Whom should I believe? Static analyzer or Leak instrument?
your problem is how you release it:
- (void)viewDidLoad{
[super viewDidLoad];
self.tstImageView = [[UIImageView alloc] //<==This object is leaking
initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
[tstImageView release]; // << here
}
you should do it this way:
- (void)viewDidLoad{
[super viewDidLoad];
UIImageView * imageView = [[UIImageView alloc] initWithFrame:<SomeFrame>];
imageView.image = [UIImage imageNamed:#"SomeImage.png"];
self.tstImageView = imageView;
[imageView release];
[self.view addSubview:self.tstImageView];
}
The checker is correct because it cannot assume that the variable is identical to the one you set. Therefore, the form you use in the OP could introduce a reference count imbalance because the ivar's value may not be what you assigned to it by the time you message release upon the ivar.
These cases are not likely for a UIImageView, and quite unlikely in the context of your program, but these examples should give you an idea as to why the checker assumes that object->ivar associations shall not be trusted:
Between creation of the image view and the message to release it via the ivar, you have:
self.tstImageView = [[UIImageView alloc] initWithFrame:<SomeFrame>];
self.tstImageView.image = [UIImage imageNamed:#"SomeImage.png"];
[self.view addSubview:tstImageView];
1) assignment of the image view via the setter
2) access of the image view via the getter
3) direct access of the ivar, when adding to self.view
the setter may have taken a copied or used a cached value. UIImageView is a bad example, but the checker does not know how types are generally passed around - even if it did, it would (at times) make unsafe assumptions.
the simplest example would be:
- (void)setName:(NSString *)inName {
NSString * prev = name;
if (inName == prev) return;
if (0 == [inName count]) name = #"";
else name = [inName copy];
[prev release];
}
the value held by the ivar could change in the meantime. not likely an issue in this case, but let's say that adding the image view as the subview could end up calling back and altering self in the process/effect of adding the subview, and replacing or removing the image view you passed. In that case, the variable view you passed would leak and the view it replaced it with would have a negative imbalance.
Neither of those are likely to happen in your example, but it does happen in real world programs, and the checker is correctly evaluating based on locality, not property (the checker can't assume much of what happens inside a method call). It also encourages one good idiomatic style in this case.
EDIT : Is there any leak there?
Well I run the above project using
Leak tool in instrument..It didn't shown any leak even though I tried
it many times..Whom should I believe? Static analyzer or Leak
instrument?
The static analyzer says there is a potential leak because it is unable to guarantee the reference/allocation it follows is correctly retained/released. You can guarantee that reference counting is correct and please the static analyzer by changing you program to look like I wrote it in my example.
The way you have written it has made it impossible for the analyzer to follow the reference.
If you have no leaks and no zombies, then there is not a leak. But the solution is easy to fix - and programs have a way of changing during development. It's much easier to use the form I posted so it is easier for the toolset and for you to verify the program is correct. The static analyzer is not always correct, but you should adjust your programs to please it because static analysis is very useful. The program I posted is also easier for a human to understand and confirm that it is correct.
when you declare a property with retain like this
#property(nonatomic,retain) UIImageView *tstImageView;
a setter is added that will incr the retainCount when you assign to the property. When you do as below the object you created has already a retainCount == 1
self.tstImageView = [[UIImageView alloc]
initWithFrame:<SomeFrame>];
so the tstImageView object has 2 in retainCount.
do instead
UIImageView* view = [[UIImageView alloc] initWithFrame:<SomeFrame>];
self.tstImageView = view;
[view release];
then, although unrelated to your leak when you release it write like this instead
self.tstImageView = nil;
since the setter will then will properly set the retainCount

Why does this cause memory leaks?

I'm new to Objective-C, and I've read some memory management articles but am having trouble.
I hava a class something like this:
-(UIWebView*)getWebView{
//UIWebView* webview = [UIWebView initWithFrame:self.frame]; edited,the original wrong line
UIWebView* webview = [[UIWebView alloc] initWithFrame:self.frame];
return webview;
}
-(void)addToSelf{
UIWebView* view = [self getWebView];
[self addSubview:view];
[view release]; //release here
}
In my thought, objc objects are all like C pointers (it is ?)
And thinking like this:
UIWebView* webview = [[UIWebView alloc] initWithFrame:self.frame]; //retain +1
UIWebView* view = [self getWebView]; //just a pointer to the same object ?
[self addSubview:view]; //retain +1
[view release]; //retain -1
Now view's retainCount = 1.
Then this viewController will handle the webview's life cycle.
There must be something wrong with my thought (sure also the code),
but I don't know why .
UIWebView* webview = [[[UIWebView alloc] initWithFrame:self.frame] autorelease];
When I remove the last release line, code works fine, why?
What's the difference?
--------------edit line---------------
Few minutes ago , there's an answer about it but it's disappeared , now I rewrite my thought:
The answer says:
When returning object from method , i must use autorelease to tell compiler I have end with it, and then using addSubview , finish (no need releasing).
I know this is right , but why it's right ?
In most of codes:
-(void)someMethod{
UIWebView* webview = [[UIWebView alloc] initWithFrame:self.frame];
[self addSubview:webview];
[webview release];
}
this works fine, but when separate the code to two methods like the top ,it's not.
Why i must use autorelease when returning object?
It looks as if you don't alloc the UIWebView:
UIWebView* webview = [[UIWebView alloc] initWithFrame:self.frame];
That means you probably don't have a valid UIWebView, and a retain count that is undefined, since the code for UIWebView is actually using some unknown piece of memory. If this works, you are lucky.
Your general idea of how retains and releases balance each other is correct. When you remove that last retain call, you are leaking. This is a defect that won't be noticeable unless you're observing memory use. (Leaks are important on any computer, but have a greater impact on handheld devices.)
In practice, if a method creates (alloc) and returns an object, autorelease it. The caller can then just use that object, and not worry about its lifetime.
*#1: Method that 'alloc's should have the responsibility to call the release-statements on the object.
#2: When you create a separate method to alloc an object for you, you cannot have 'release' statement, since that will release the object even before call site method uses it. Hence, instead of calling release we call autorelease and thus obeying the principal of #1, but still allowing call-site to use the object. As call-site didn't do any alloc by itself, it also does not have to worry about any releases.***

Why do we need a temporary object?

As I have seen in many examples, first they allocate memory for the temporary object and later the same object is assigned to self. For example, I have a code snippet here :
-(void)viewDidLoad {
[super viewDidLoad];
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];
self.movie = newMovie;
}
Why cant we perform like:
self.movie =[[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];
Both are essentially the same. They adhere to the ownership clause – You release what create/retain. The difference, though not so obvious here, is that the time it takes for an autoreleased object to be released. Say, if loads of such autoreleased objects lingered around in the memory, this could create memory problems. If we released them and their retain count is zero, they are immediately deallocated and memory is freed up.
You don't need the temporary object. Your suggestion is perfectly valid.
However, if you need to set properties or call methods after creating the object, using a temporary object may be a little nicer than calling self.movie multiple times:
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ] autorelease];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
Personally, I do not use autorelease in that scenario, but that's more a style preference:
Movie *newMovie = [[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
[newMovie release];

Should I retain or assign the viewcontroller in this case?

Interface
#property (nonatomic, retain) PracticalSignsMainViewController *practicalVC;
Implementation
if (self.practicalVC == nil) {
PracticalSignsMainViewController *vc = [[PracticalSignsMainViewController alloc] init];
self.practicalVC = vc;
[vc release];
}
I only want to make one viewcontroller object in this case and change the data that it acts upon. However is it correct to retain or assign this viewcontroller (and why so)? It is used in a navigation-hierachy.
Thanks.
Retain. Typically you want object properties to be retained, and primitive properties to be assigned. The answer here is really good: Use of properties for primitive types
If you're planning to cache a view controller that's used in a navigation, you would need to retain it. The reason is that while the navigation controller retains it temporarily, once the user hits the back button the navigation controller will send the view controller a release message. If you haven't retained the view controller anywhere else at that point it will be deallocated.
If you're creating a new instance each time, that would be fine, but obviously that would destroy a cached instance if the property uses assign semantics.
Firstly, your code is right, but it can be more simple.
If you did the following synthesize,
#synthesize practicalVC; // synthesize release the existing reference if has
the following code is same as your code.
self.practicalVC = [[[PracticalSignsMainViewController alloc] init] autorelease];
As you mentioned, if your app does not need many access to the view controller, you need not to have view controller's instance separately.
============== Modified ====================
And I modified my answer after seeing answers of #6NSString #Abizern.
Regarding autorelease and coding style.
1. autorelease,
#6NSString said that "it uses autorelease which many avoid unless returning an newly alloced object."
But even if you use "autorelease" in return statement, the retain count of the returned object is not immediately decreased. It will be decreased at an appropriate time.
So If we want to decrease the retaincount explicitly and immediately, we should use paired "release".
-(NSObject*)testAuto {
return [[[NSObject alloc] init] autorelease];
}
...
self.anObj = [self testAuto];
// the retainCount of anObj is 2
..
-(void)testAuto {
self.anObj = [[[NSObject alloc] init] autorelease];
}
...
[self testAuto];
// the retainCount of anObj is also 2
..
-(void)testAuto {
self.anObj = [[[NSObject alloc] init] autorelease];
[self.anObj release]; // Yes, yes, you may say this code does not look good. :)
}
...
[self testAuto]
// the retainCount of anObj is 1
...
As you see, (I naturally tested above code again) "autorelease"s both in return statement and in alloc statement are almost same. And if you want to manage retain count harder, we should use "release".
I think "autorelease" in alloc statement is better than one in return statement because "autorelease" in return can be omitted. :)
2. Coding style,
As the end of "1. autorelease", I think, autorelease in alloc statement would be more safe to avoid missing release.