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];
}
Related
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.
Part of my code presents a UITableViewController in the following way:
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
flipside = [[UINavigationController alloc] initWithRootViewController:controller];
controller.delegate = self;
flipside.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:flipside animated:YES];
[flipside release];
[controller release];
Using the leaks tools, no memory leaks are picked up on. However, whenever I bring up the settings menu (as shown in the code above), more memory appears to be allocated and never released - almost 100 kB every time.
Weirdly, the inclusion of the two release statements at the end seems to have no effect on the memory allocation..? Is there something I am misunderstanding about memory allocation in objective-c, or is something weird going on?
Any ideas are much appreciated - thanks!
If flipside is a retained property then the navigation controller is leaking. the problem is that you are bypassing the accessor method and releasing flipside directly. This is just messy code. A better way to do it would be to make an accessor method for flipside that will only alloc a new one if you haven't already created one. It's called lazy loading. To do this, just leave the #synthesize for flipside (but you shouldn't set it from outside the accessor method), in your header file change the property to, and add this method to the implementation:
- (UINavigationController *)flipside {
if (flipside != nil) {
return flipside;
}
FlipsideViewController *controller = [[[[FlipsideViewController alloc] initWithNibName:#"Settings" bundle:nil];
controller.delegate = self;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller release];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
// This implies a retain if your flipside property is set to retain
self.flipside = navController;
[navController release];
}
make sure to put self.flipside = nil in the viewDidUnload method of the view controller the code you included came from (I assume it's a presentSettings action).
what your presentSetting action should now look like is this:
- (IBAction)presentSettings {
// make sure you use the accessor self.flipside instead on accessing the variable directly
[self presentModalViewController:self.flipside animated:YES];
}
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
Hi I have a very basic issue of memory management with my UIViewController (or any other object that I create);
The problem is that in Instruments my Object allocation graph is always rising even though I am calling release on then assigning them nil.
I have 2 UIViewController sub-classes each initializing with a NIB;
I add the first ViewController to the main window like [window addSubView:first.view];
Then in my first ViewController nib file I have a Button which loads the second ViewController like :
-(IBAction)loadSecondView{
if(second!=nil){ //second is set as an iVar and #property (nonatomic, retain)ViewController2* second;
[second release];
second=nil;
}
second=[[ViewController2 alloc]initWithNibName:#"ViewController2" bundle:nil];
[self.view addSubView:second.view];
}
In my (second) ViewController2 i have a button with an action method
-(IBAction) removeSecond{
[self.view removeFromSuperView];
}
Please let me know if the above scheme works in a managed way for memory...?
In Instruments It does not show release of any allocation and keeps the bar status graph keeps on rising.
First of all, why use this scheme when second is a property:
if(second!=nil){
[second release];
second=nil;
}
second=[[ViewController2* second]initWithNibName:#"ViewController2" bundle:nil];
A propery automatically releases it's old value when the setter is used. So this could be rewritten as:
if(self.second == nil) { //Prevents creating a new controller if there already is one.
self.second = [[[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil] autorelease];
}
Also, what's up with [ViewController2* second]?
Why is that asterisk there, and what does the class method second do?
Here's a hypothetical getter:
- (DetailViewController *)detailController
{
if (detailController == nil) {
DetailViewController *controller = [[DetailViewController alloc] initWithNibName:#"Detail" bundle:nil];
self.detailController = controller;
[controller release];
}
return detailController;
}
Then the code that calls it looks something such as:
- (void)loadControllerOrSomething
{
DetailViewcontroller *controller = self.detailController;
[navigationController doSomethingWith:controller];
}
My question regarding memory management is the following. If I let *controller go out of scope here, in loadControllerOrSomething, am I leaking memory? Should I be doing a controller = nil after working with navigationController?
No you won't leak anything.
There was no additional retain added to the controller before it was returned, and no retain added when it was received. If you need to guarantee it's existence outside the scope of your functions you should call retain on it, and release when done.
This is generally how memory management works in Cocoa. When an object is returned by a function you have no ownership rights. Unless you call 'retain' it will be deleted by when it reaches the end of its natural lifecycle which could be the next frame, the next minute or so on.
The exception are functions with names containing 'alloc' or 'copy' and that return a new object. You are responsible for calling release when they are no longer needed.