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).
Related
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.***
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.
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
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.
Instruments says I have leak in this function. I am new to Obj-C so pardon for missing something obvious besides I am not sure if I am doing everything right here.
(void) selectList:sender {
NSMutableString *nibName = #"myController";
MyOwnController *study = [[MyOwnController alloc] initWithNibName:nibName bundle:nil];
study.title = #"Fundamentals";
study.listNameToLoad = #"funds";
[self.navigationController pushViewController:study animated:YES];
[nibName release];
[study.title release];
[study.listNameToLoad release];
[study release];
study = nil;
}
Related questions. Once you do pushViewController should you always do a release on the controller you just pushed on the stack ?
You should read this first.
In summary, you release only if you create or copy. You have released quite a few variables which you haven't created/copied and is not your responsibility to release. You should hence not release nibName, study.title & study.listNameToLoad.
Again, You should release the 'title' and 'listNameToLoad' properties within the controller's dealloc method.
As for your related question, you can release the controller only if you don't need the reference any more. If you do choose to keep the reference, you need to release the reference later when you don't need it any more.