I have a view controller. The view controller has a retained object called streamController, which is an NSObject subclass that handles all of the data I/O with my server. All is well, except I'm trying to figure out why some things are leaking on said streamController. I drop an NSLog in there and I never see it firing. I'm completely puzzled as to why, because I'm releasing the controller in my dealloc method for my view controller.
from view controller interface...
StreamController *streamController;
#property (nonatomic, retain) StreamController *streamController;
from view controller implementation...
#synthesize streamController;
- (id)init {
[super init];
self.streamController = [[StreamController alloc] init];
}
- (void)dealloc {
NSLog(#"dealloc view controller");
[streamController release];
[super dealloc];
}
from StreamController implementation...
- (void)dealloc {
NSLog(#"dealloc stream controller");
[super dealloc];
}
this last dealloc NEVER gets called. Why?
I believe you are just leaking memory,
if your property has retain attribute then you should take a look at the following examples:
//A
self.streamController = [[StreamController alloc] init];
//B
StreamController * st = [[StreamController alloc] init];
self.streamController = st;
[st release];
//C
streamController = [[StreamController alloc] init];
if you check retain counts you will see that in A approach your streamController object will have a retainCount of 2, while in B it will be only 1.
Reason:
In A by doing [[StreamController alloc] init]; your object has already a retainCount of 1 before passing it to your property. Then, since you declared it as retain, it will be retained, hence it's retainCount becomes 2.
In B is basically the same but you are releasing the object just after you pass it to your property. Hence, it ends with it's retainCount in 1. (This is what we want)
In C you are not using the property, you are setting the value directly. Hence it will be retained only once. This is fine in this case because is the initialization.
I will suggest to use B or maybe C if you are sure that streamController is nil (like the initialization of your object)
Hope this helps
Related
I have a UILabel in my class header file defined as :
`#property (nonatomic, retain) UILabel *label1;`
and it exists as instance variable like this:
`UILabel *label1;`
and synthesized in the .m file, however, in viewDidLoad method I do:
`label1 = [UILabel alloc] init] autorelease];`
then I do various things on the label like setting its frame, text color, etc ...
when the view controller is deallocated, the app crashes with this message in console
(Zombies enabled): `[CALayer release] message sent to deallocated instance` ...
The app will not crash when I :
1) remove the autorelease word .. or
2) if i do not release label1 in the dealloc method .. or
3) remove [super dealloc]; from the dealloc method of the view controller.
how can I properly release this UILabel without facing such crash !!
You are doing right.Autorelease and release in dealloc.
But it shouldn't be crash.Because I did the same thing to check.
Could you please check accciendlty may be u release the label some where else.
And releasing in dealloc again.
since you have declared the label as retain. The allocation can be
UILabel *myLabel = [[UILabel alloc] init];
// set all properties of label
self.label1 = myLabel;
[myLabel release];
myLabel = nil;
And in dealloc release your label1.
[label1 release];
this is the way I'm used to and this makes things smoother for me.
the label is released already before dealloc is called. that is because its an autorelease object. your dealloc is trying to release a UIlabel that already been released, an it crashes.. in your question. you can use 1 or 2. if you allocated the object once, then call a release just once. its not because you assign retain to your property in #property directive will add 1 retain count to your object , #property(retain) will not allocate anything, but will tell the compiler how you want your properties treated
strangely enough, when I used self.label1 = [[[UILabel alloc] init]autorelease]; instead of label1 = [[[UILabel alloc] init] autorelease]; solved the problem. the dealloc method remains as is without any change. really weird !!
Do this and u will not use autorelease for label1:
- (void)dealloc
{
if(label1)
{
label1 = nil;
[label1 release];
}
[super dealloc];
}
I have some problem with my singleton and UIViewController there;
Singleton.h
#property (nonatomic, retain) UIViewController *viewController;
Singleton.m
...
#synthesize viewController = _viewController;
- (void)load {
self.viewController = [[[UIViewController alloc] initWithNibName:#"NibName" bundle: nil] autorelease];
}
- (void)unload {
[_viewController release];
}
This viewController using by different part of the application via pushViewController:animated:. But sometimes I need to release viewController by calling method - (void)unload of Singleton class! If pushViewController:animated: never call for viewController everything is well and dealloc is calling, but if pushViewController(and viewController perform viewDidLoad), dealloc isn't work. If I do something like self.viewController = nil; dealloc calling twice... What I'm doing wrong???
Your unload function should only consist of:
- (void)unload {
self.viewController = nil;
}
When you set a retained property to nil, it releases the instance variable AND nils it. You are simply leaving a dangling pointer on your property here.
You need to set it to nil after releasing it:
[_viewController release];
_viewController = nil;
Otherwise the next person who comes along will try to do stuff with an invalid pointer.
i have a problem when going to another controller with the following buttons
-(IBAction)art:(id)sender{
TestYourInfoViewController *test = [[TestYourInfoViewController alloc]
initWithNibName:#"TestYourInfoViewController" bundle:[NSBundle mainBundle]];
test.questionType = #"art";
testYourInfoViewC = test;
[testYourInfoViewC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self.navigationController presentModalViewController:testYourInfoViewC animated:YES ];
[test release];
}
and when i go back with the following
-(IBAction)back:(id)sender{
[[self parentViewController] dismissModalViewControllerAnimated:YES];
}
it crash the application with no stacktrace.. what is the wrong with that please.
Is testYourInfoViewC defined in the header as a retained #property? If so, you should always be referring to it using self and dot notation.
- (IBAction)art:(id)sender
{
TestYourInfoViewController *test = [[TestYourInfoViewController alloc]
initWithNibName:#"TestYourInfoViewController" bundle:[NSBundle mainBundle]];
test.questionType = #"art";
self.testYourInfoViewC = test;
[self.testYourInfoViewC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self.navigationController presentModalViewController:self.testYourInfoViewC animated:YES ];
[test release];
}
When you create a retained #property and #synthesize it, a setter is being created that handles the memory management involved in retaining the new object and releasing the old, but by assigning test to testYourInfoViewC you're bypassing that synthesized setter.
Let's step through this here. You've created test using alloc/init, thus setting its retainCount to 1. Next you've assigned testYourInfoViewC to test. No change in the retain count, testYourInfoViewC is now simply pointing to the same object as test instead of retaining a copy for itself.
Now when you call release on test that retain count returns to 0 and the object is deallocated. Your instance of TestYourInfoViewController is completely gone and testYourInfoViewC is now left flapping in the wind. When attempting to dismiss it, the parentViewController is going to attempt to send some messages to that object behind the scenes, like -viewWillDisappear:, -viewDidDisappear: etc.
Edit: Here's how I handle this kind of situation in my projects. I override the getter for the property and determine whether it needs to be created or not. This way I can call the property anywhere in my code and I can be assured that if its not created it will be allocated, initialized and setup just in time.
- (TestYourInfoViewController *)testYourInfoViewC
{
if (!testYourInfoViewC)
{
testYourInfoViewC = [[TestYourInfoViewController alloc] init]; // This will work because the .xib and class name are identical.
[testYourInfoViewC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
}
return testYourInfoViewC;
}
After you've setup the getter to provide lazy instantiation, your -art: method will look like this...
- (IBAction)art:(id)sender
{
[self.navigationController presentModalViewController:self.testYourInfoViewC animated:YES];
}
First thing i do is create a ViewController and push it to the Navigation Controller.
viewController = [[MyViewController alloc] init];
[navController pushViewController:viewController animated: NO];
[viewController release];
Retain count is 2 now (pushViewController uses 2 retain apparently but not my responsibility) so far so fine.
Inside MyViewController i'm createing a instance of a class and sets the ViewController as delegate to the instance.
timer = [[MyBackgroundTimer alloc] initWithInterval:20];
[timer setDelegate:self];
Now the viewControllers retain count has increased by 1 becouse of setDelegate:
But when i'm releasing the viewController later it will never call dealloc becouse i have one more retain count.
How should you correctly drop the retain count when you set your self as delegate?
Don't retain your delegate. If you're using a property, define your delegate as assign, not retain. Somebody else needs to retain your delegate, not you.
Your class MyBackgroundTimer should have the delegate property as assign and not retain.
#property (nonatomic, assing) id delegate;
And this class should retain the delegate just when it needs to use it, and release when it is done.
#implementation MyBackgroundTimer
#synthesize delegate;
-(void) startTimer {
[self.delegate retain];
//... do some actions
}
-(void) timerStopped {
//... call delegate methods
[self.delegate release]
}
#end
It is important to remember that you can have your delegate as a retain property. But to do so the right way, you have to ensure that you release it before dealloc is called (like the timerStopped method in the example above)
I say that because if you try to release the delegate at the dealloc method, the class that instantiates MyBackgroundTimer is the same class as the delegate, and it also releases MyBackgroundTimer at the dealloc (which is pretty much the common case), the dealloc method of both classes will never be called, as each class will have the ownership of the other, resulting in a memory leak (that will not be shown at instruments).
I have a view controller that was presented using
[self presentModalViewController:myVC animated:YES];
this VC has several declared retained properties (#property) that I have to release on its dealloc.
The variables are declared as
#property (nonatomic,retain) myClass1 *myProperty;
#property (nonatomic,retain) myClass2 *myProperty2;
// etc... and then synthesized on .m
The problem is that when I dismiss the viewController using
[self dismissModalViewControllerAnimated:YES];
it crashes on the dealloc, when releasing the retained properties I have declared, with the error *modifying layer that is being finalized *
Apparently the the viewController is gone at the time its own dealloc runs and then it crashes.
How do I solve that? Thanks in advance.
edit
the code that presents the viewController is on the rootViewController and is this:
UIViewController *myVC = [[UIViewController alloc] init];
myVC.delegate = self;
UINavigationController *navigator = [[UINavigationController alloc] initWithRootViewController:myVC];
[self presentModalViewController:navigator animated:YES];
[navigator release];
[myVC release];
and this is the what the dealloc code on myVC contains
- (void) dealloc {
[myProperty1 release]; // see this properties at the beginning of this question
[myProperty1 release]; // if I comment these 2 relesases it stops crashing
[super dealloc];
}
myVC is dismissed from inside itself, but that's fine according to the docs. I have also tried to dismiss it from the rootviewController but it continues to crash. The only way to stop crashing is to disable the release lines on the dealloc.
How do you set the properties?
self.myProperty =
? My guess is that you do not retain them. Are you doing
myProperty = ...
by any chance, with neither a retain or self.? The setter you synthesize needs a chance to actually retain your newly created object...
So in full it should read something like this:
MyClass1 *aProperty = [[MyClass1 alloc] init];
self.myProperty1 = aProperty;
[aProperty release];
...i asked where you allocate and init "myProperty1" and "myProperty2"...
i'm afraid that you make confusion thinking that this:
#property (nonatomic,retain) myClass1 *myProperty;
#property (nonatomic,retain) myClass2 *myProperty2;
need that you release myProperty and myProperty2
well, you are wrong!
you are just declaring the kind of objects you are going to use, not allocating them
you need to release them just if you alloc them someWhere...