Is it ok to autorelease UIViewControllers? - iphone

I have some view controllers:
StockTwitsTVViewController* stvViewController = [[[StockTwitsTVViewController alloc] initWithNibName:#"StockTwitsTVViewController" bundle:nil]autorelease];
UINavigationController *stvNavController = [[UINavigationController alloc] initWithRootViewController:stvViewController];
stvNavController.tabBarItem.image = [UIImage imageNamed:#"today-icon.png"];
ScheduleViewController* scheduleViewController = [[[ScheduleViewController alloc] initWithNibName:#"ScheduleViewController" bundle:nil]autorelease];
scheduleViewController.title = #"Archives";
UINavigationController *scheduleNavController = [[UINavigationController alloc] initWithRootViewController:scheduleViewController];
scheduleNavController.tabBarItem.image = [UIImage imageNamed:#"archived-icon.png"];
stvTabBarController = [[UITabBarController alloc] init];
stvTabBarController.delegate = self;
stvTabBarController.viewControllers = [NSArray arrayWithObjects:stvNavController, scheduleNavController, nil];
stvTabBarController.selectedViewController = stvNavController;
[stvNavController release];
[scheduleNavController release];
[self presentModalViewController:stvTabBarController animated:YES];
Is it ok to auto-release them or is it better practice to manually release? Why?

What you do in your code is perfectly fine. To make things more consistent I would also create stdNavController and scheduleNavController as autoreleased objects.

Read mikeash.com: Autorelease is Fast.
What he didn't test was autorelease versus release. When I tested, a million [[[NSObject alloc] init] autorelease] plus the autorelease pool overhead took on the order of twice as long as [[[NSObject alloc] init] release]. Admittedly, I tested on 10.6 (presumably if it's still refcounted since I didn't enable GC), but the relative performance still holds.
Maybe autorelease uses a couple of microseconds of CPU time, but it sure beats adding a memory leak because you changed an ivar to a local, or you copy-pasted code around and forgot the release.
Care about performance when it matters. When it does, you might decide to use CFString instead of NSString and ivar access instead of property access and function calls instead of class methods. In general, though, it's important to write code that is easy to maintain, even if that means using 1% more CPU.

The autorelease will let the release to be done later by the OS, it means when the current run loop finishes.
The release inform the OS that the object id not necessary anymore and that the allocated memory can be freed.
For performance on iOS it's better to use release, instead of autorelease because the system can claim back the allocated memory straightaway.

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).

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];

(iphone) basic memory management question

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

Why is this code producing an memory leak?

The Leaks Instrument in Xcode shows me an memory leak here. I have commented the affected line which Leaks is complaining about. But I see no error in my memory management...
- (void)setupViewController {
MyViewController *myVC = [[MyViewController alloc] init];
UITabBarItem *tbi = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemDownloads tag:1];
myVC.tabBarItem = tbi; // LEAK: 128 bytes
self.myViewController = myVC;
[myVC release];
[tbi release];
}
I mean... tbi and myVC IS released at the end, and the alloc IS balanced. So what's wrong? I don't get it.
if MyVc.tabBarItem is already set, whatever it's pointing at may not be deallocated properly, causing a leak.
It just goes to show that at least one of the following statements is true:
Instruments is not perfect and sometimes shows leaks where there aren't any (and vice versa).
Apple's code is not bug-free.
In fact, both are true.