viewController object BAD_ACCESS in iOS5? - iphone

Usually when we push viewcontroller, we will create object for view controller, after that line we will push and release it.
But it gets crashed when we run in iOS5. So I retained the object through propery and declare it in interface as global. Now it is working fine. Will retaining viewcontroller occupy much memory? What is the difference between following two approches?
One:
MyViewCOntroller *obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:obj Animated:YES];
[obj Release]
Two:
self.obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:self.obj Animated:YES];
[self.obj Release]

The first one should be right and please detect for the crash reason again. It can't be crashed when you use the first one to push a new view controller.
As for the difference: in the second one, if you declare the obj as a var of self class and you don't use ARC, you take care of obj like the other instance vars. You just need to do release in the dealloc.

Generally speaking, you should not release property(self.obj) in methods except for dealloc.
The second code snippet should be replaced like this:
self.obj = [[MyViewCOntroller alloc] init];
[self.navigationController pushViewController:self.obj Animated:YES];
And add below one to your dealloc method:
self.obj = nil; // Property will release itself and set the point to nil
The first code snippet is OK, you alloced local instance and released it after used.

why aren't you init your view controller with nib?
SearchView *secondViewController = [[SearchView alloc] initWithNibName:#"SearchView" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
be careful with retaining any objects. You must be completely sure that you init it only onse and then release it. If you do so, you may not care about memory. The difference between your inits is: in 1st case you creating ner object. It is NOT retain, but, may be leak, I'm not shure. I think you should add autorelease. In 2nd case you have an object's property (probebly, retain?) in header. you must release it in dealloc method

Are you passing the View Controller to the new Object?
If yes, Are you releasing this View Controller property in the new View Controller's dealloc method? That would be a double release.
Example no. 2 would solve this problem because of the (retain) type property it may have in the old View Controller, would set its retain count to 2.

Related

application crashed after dismiss presentModalViewController

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

unload View after calling presentModalViewController?

I have some view controller which I call with the following method:
myViewController *myView = [[myViewController alloc] initWithNibName:nil bundle:nil];
myView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:myView animated:YES];
[myView release];
if I use the app a few times I get a memory warning and the app freezes for a few seconds! I think the reason is that i switch the view but not discharged the old one !!?!!?!!
(i set my outlets to nil and release them)
how can I unload the old view after switching to the new one?
Thanks in advance
When switching the view be sure to call dismissModalViewController:(BOOL)animated on myViewController.
In the class that launch the modalViewController you could make a property for the modal viewcontroller which you retain. Then you could write something like this.
//This would be in an action or something...
if (self.myViewControllerProperty == nil) {
self.myViewControllerProperty = [[[MyViewController alloc] initWithNibName:nil bundle:nil] autorelease];
}
[self presentModalViewController:self.myViewControllerProperty animated:YES];
Then instead of setting the
myView.modalTransitionStyle =
UIModalTransitionStyleCoverVertical;
Move that code to the modalViewController and write self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; I think that looks cleaner, keep the configuration of each viewcontroller separted don't mix it up.
And as the maclema said, call dissmissModalViewController, but you probably are doing that...
Could be any number of problems but you don't need to (and can't) unload the old view. Make sure you are releasing objects and setting outlets to nil in viewDidUnload of all of your view controllers. viewDidUnload will be called when a memory warning occurs so if you don't handle it correctly you'll have leaks and can crash. Other than that, hard to know what else your app is doing that is contributing to the crash.

NavigationController initWithRootViewController dealloc

I have some pretty simple code where I am using a UINavigationController and adding a rootViewController. After some processing has occurred I want to pop off the current view controller and replace it with another one. This seems to work fine, but my original view controller does not dealloc. I set a breakpoint in it's dealloc and it never gets hit. Below is my code. Not sure why happens. Just for testing if I release startController twice it does go away.
StartViewController *startController = [[StartViewController alloc] initWithNibName:#"StartViewController" bundle:[NSBundle mainBundle]];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:startController];
[nav pushViewController:startController animated:NO];
self.navController = nav;
[startController release];
[nav release];
Thanks any help.
Your ultimate goal is to bring the view controller's retain count to zero. So make sure that everything the view retains is released and anywhere the view is retained also release.
Please check the following possible causes:
Make sure you pop the view controller from the navController if you have a custom back button. The default Back button will work fine.
Make sure that all your IBOutlets are set to nil in viewDidUnload
- (void)viewDidUnload
{
[super viewDidUnload];
self.webView = nil;
}
If your view is an observer to a model class to receive events
For example
model.addObserver(myView);
and sure to also do
model.removeObserver(myView);
I hope this helps.
It looks as though your self.navController has got a holding reference to it. maybe put
self.navController =nil;
somewhere appropriate, so that when the view has been popped it is released.
I was trying to pop off the root view controller. I instead used the setViewControllers message from the UINavigationController object to replace all my view controllers.

when to alloc and initialize a view controller

recently I joined two Xcode projects together. To get this thing to work, I had to alloc and initialize my view controller.
self.myViewController = [[MyViewController alloc] init];
But why? In the other project I have the same code. The sole difference is hierarchy of the different views. I added a new view to the top (beginning). So the calling View Controller is not the first view on the stack anymore.
I'm pushing my view in this way on the stack:
[[self navigationController] pushViewController:myViewController animated:YES];
In my NIBs I have added a View Controller object with IB and connected the Outlets.
And I have a memory management question too: If I have a property like myViewController, do I have to release it? The "normal" release is done in the dealloc method. But do I have to use an additional release because of the alloc? I don't think so, but I ask you anyway.
I would need to see more code to answer why you had to alloc your view controller, but I'd say that you always alloc them manually (at least in my experience).
As for the memory management question, if your property is declared as a retain property (#property(retain) UIViewController *myViewController), you are indeed leaking memory, since the retain count after alloc will be 1, and after the retain done by your accessor will be 2. Hence, if you release it only once, you'll end up with a leak.
I usually do this instead:
self.myViewController = [[[MyViewController alloc] init] autorelease];
I found it out: In IB I had to set the nib name on my view controller object. So the alloc and initialization is done by IB?
There is one more option:
(IBAction)loginButton:(UIButton *)sender {
NSLog(#"pressed login");
ICMasterViewController *controller = [[self storyboard] instantiateViewControllerWithIdentifier:#"mainnav"];
[self presentViewController:controller animated:YES completion:nil];
}
On your storyboard you must have UIViewController with name mainnav

Memory allocation in Objective C

I have a simple question. I was referring "Your first iOS application" document by apple.I found that the class has a property called myViewController:
#interface applicationClass
{
MyViewController *myViewController
}
Now to assign a memory to this pointer, the code shown is:
MyViewController *aViewController = [[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
My doubt here is, what is wrong if this is done as follows:
self.myViewController = [[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
I cannot find this kind of instantiation where a property is assigned directly in many of the documents. Instead, a temporary memory is allocated and then it is retained by the property. Can anyone guide me if I am wrong ?
If you call methods which have alloc or copy in their names you get objects with a retain count of +1 and thus you are responsible for releasing it after use.
Now, if you assign to a property that is defined as #property(retain,...) ... then the #synthesize'd method takes care that retain and release are called correctly. So if you do self.foo = bar then the retain count of bar is increased by one.
Here, you got an object with retain count 1 from your alloc/init. Then you assign it to your property, and the retain count climbs to 2, which is too high (you only have one reference to it, not two). Two solutions: either the first code block you've cited, it stores the object in a variable and can then call release to immediately "fix" the retain count to 1 again. Or, you can do this:
self.myViewController = [[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]] autorelease];
The autorelease will make sure that at a later time release is being called on the object thus again "fixing" the retain count. You cannot replace autorelease withrelease` here as the retain count would drop to 0 before it gets assigned to the property, thus it would get deallocated before it gets passed to the property.
With this you are retaining your object twice: in self. (if you have set retain in your property of couse) and in [MyViewController alloc]. You only want to retain the object once ....