Hi I was wanted to do Application witch have a root template view with a nice logo on top or something adn load other views just below
(here is what I have right now: Test App
)
But I have a little problem. If I'll remove a comment in file TestAppDelegate.m on line 58
//[currentView release];
Application will crash with bunch of errors when I try to switch views.
But if I comment this line Project analyzer is telling me that I have a potential leak
with currentView variable.
Can somebody spare some time and see in that code what I did wrong?
The problem is that you are only adding currentView.view as a subview so that is being retained elsewhere but currentView itself is not. This means that when you release it, it is consequently dealloc'd and its view will have difficulty working without it.
One solution would be to have currentView as an instance variable and create a property for it so that the memory mangement is done for you.
#property (nonatomic, retain) UIViewController *currentView;
and then replace a line like
currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
with
self.currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
This will release the old view controller before retaining the new one. Then lastly don't forget to release currentView in the dealloc method of the class.
I have a function and it looks like this:
- (void) switchView: (int) viewType {
for (UIView *view in [self.viewController.rootView subviews]) {
[view removeFromSuperview];
}
UIViewController *currentView = nil;
switch (viewType) {
case 1:
currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
break;
case 2:
currentView = [[Second alloc] initWithNibName:#"Second" bundle:nil];
break;
}
[self.viewController.rootView addSubview: [currentView view]];
[self.window makeKeyAndVisible];
//[currentView release];
}
Related
I'm developing an iPhone 3.1.3 app with iOS 4 SDK.
I have two ViewControllers, mainViewController and AboutViewController.
I use this code to go from mainViewController to AboutViewController (code inside mainViewController.m):
- (IBAction) aboutClicked:(id)sender
{
AboutViewController* aboutController =
[[AboutViewController alloc]
initWithNibName:#"AboutViewController"
bundle:nil];
[self.view addSubview:aboutController.view];
[aboutController release];
}
And this to come back from AboutViewController to mainViewController (code inside AboutViewController.m):
- (IBAction) backClicked:(id) sender
{
[self.view removeFromSuperview];
}
When I click on Back Button on AboutViewController, I get an EXC_BAD_ACCESS.
I'm using a window-based application template.
I've also tried to add a breakpoint in [self.view removeFromSuperview] but I can't.
Do you know why?
Do this instead:
- (IBAction) aboutClicked:(id)sender
{
AboutViewController* aboutController =
[[AboutViewController alloc]
initWithNibName:#"AboutViewController"
bundle:nil];
[self presentModalViewController:aboutController animated:YES];
[aboutController release];
}
And this to come back from AboutViewController to mainViewController (code inside AboutViewController.m):
- (IBAction) backClicked:(id) sender
{
[[self parentViewController] dismissModalViewControllerAnimated:YES]
}
The reason why you get EXC_BAD_ACCESS is because after adding the view of a viewController as sub view you released the controller, hence the touch event couldn't see the intended viewController to process it.
comment out the release statement like below and it should work
- (IBAction) aboutClicked:(id)sender
{
AboutViewController* aboutController =
[[AboutViewController alloc]
initWithNibName:#"AboutViewController"
bundle:nil];
[self.view addSubview:aboutController.view];
//[aboutController release]; To avoid leaking consider creating aboutController variable at instance level and releasing it in the dealloc.
}
Try:
[self presentModalViewController:aboutController animated:YES];
To present the view and:
[self dismissModalViewControllerAnimated:YES];
To remove the view...
1) Make aboutController a class level variable
2) Create a delegate method to handle
(IBAction) backClicked:(id) sender
3) In implementation of delegate call
[aboutController.view removeFromSuperView];
I'm sure this is some stupid mistake, but i'm trying for the past hour to remove a subview from my superview without any success.
On my first view i'm having
UIViewController *helpView = [[[UIViewController alloc] initWithNibName:#"HelpView" bundle:nil] autorelease];
[self.view addSubview:helpView.view];
And then inside helpView i have a button which is connected to an IBAction called "closeHelp" which just does the following:
- (IBAction) closeHelp{
[self.view removeFromSuperview];
}
But this causes my app to crash with EXC_BAS_ACCESS for some weird reason, even those this is inside the HelpView, meaning self.view should be pointed to the correct subview..
Would appreciate your help
Thank you.
Shai.
As Andreas answered, you are trying to remove self.view from its super/parent view.
You basically need to remove the helpView from its parent view.
so it should be
- (IBAction) closeHelp{
[helpView removeFromSuperview];
}
But we dont know what is "helpView" in the above method. As we dont have any handle for it.
So our code should finally look like this.
#define HELP_VIEW_TAG 101 // Give tag of your choice
HelpView *helpView = [[HelpView alloc] initWithNibName:#"HelpView" bundle:nil];
helpView.view.tag = HELP_VIEW_TAG;
[self.view addSubview:helpView.view];
[helpView release];
- (IBAction) closeHelp{
UIView *helpView = [self.view viewWithTag:HELP_VIEW_TAG];
[helpView removeFromSuperview];
}
The self.view does not point to your subview but the root view which your uiviewcontroller manages. You should probably remove only the last object in the subview stack, not the whole view, because now you are removing the whole help view.
Anyway, why do you not present the viewcontroller modally instead of doing this?
[self presentModalViewController:helpView animated:NO/YES];
helpView. modalTransitionStyle = //One of the constants below
UIModalTransitionStyleCoverVertical
UIModalTransitionStyleFlipHorizontal
UIModalTransitionStyleCrossDissolve
UIModalTransitionStylePartialCurl
Usually I am writing self.modalTransitionStyle = // One of the constants
in the viewcontroller which will be presented modally, instead of spreading the code.
You are initializing helpView as a UIViewController.
Make sure you have #import "HelpView.h" (or whatever the helpView .h file is called) in the .h file of the view controller where you are initializing it.
Then, use this code:
HelpView *helpView = [[HelpView alloc] initWithNibName:#"HelpView" bundle:nil];
[self.view addSubview:helpView.view];
That should fix it.
The easiest solution for me eventually was to just define my XIB's file owner as the same class as the parent controller, meaning the parent controller would control both the parent and the subview, which just makes a lot easier. :)
Declare the help view on calss level.
in.h file
#class HelpView;
..
#interface
{
HelpView *helpView;
}
#property(nonatomic,retain)HelpView* helpView;
In.m file
#import "HelpView"
#synthensize helpView;
now add this Code where you want
helpView = [[HelpView alloc] initWithNibName:#"HelpView" bundle:nil];
helpView.view.tag = HELP_VIEW_TAG;
[self.view addSubview:helpView.view];
- (IBAction) closeHelp{
//UIView *helpView = [self.view viewWithTag:HELP_VIEW_TAG];
[helpView removeFromSuperview];
}
-(void)dealloc
{
[helpView release];
}
I have a simple app with only location services and 3 (almost empty) different views, and from some reason I can't get from view 1 to view 2 - app crashes and I get an exception. View 1 is the original .xib file, the two others are just views that I added later. It's weird cause I can switch between all of them (1->3, 2->1, 2->3, etc..) just not from 1->2.
I use this code in #1 view controller m. file:
- (IBAction) switchToMaps : (id)sender //this is the one that doesnt work
{
MyMap *mapsView = [[MyMap alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:mapsView animated:YES];
}
- (IBAction) switchToThird : (id)sender
{
ThirdView *third = [[ThirdView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:third animated:YES];
}
and as another example, here is the code from the 2nd view controller (MyMaps.m):
- (IBAction) switchBack : (id)sender
{
LastLocationViewController *firstView = [[LastLocationViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:firstView animated:YES];
}
- (IBAction) switchFront : (id)sender
{
ThirdView *lastView = [[ThirdView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:lastView animated:YES];
}
I know it's super vague, but any ideas what can cause this? I have no idea how to debug this...I even put breakpoints at the beginning of each IBAction method, and when it crashes, it doesnt even stop there....before I added this code, this app (which has only location) worked totally fine.
Any ideas?? Thanks!!
if your view does not load from any nib file then you should do like
MyMap *mapsView = [[MyMap alloc] init];
and
ThirdView *lastView = [[ThirdView alloc] init];
and in your back method
- (IBAction) switchBack : (id)sender
{
// LastLocationViewController *firstView = [[LastLocationViewController alloc] initWithNibName:nil bundle:nil]; // because you are allocating new memory to your last view
// [self presentModalViewController:firstView animated:YES];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction) switchFront : (id)sender
{
// ThirdView *lastView = [[ThirdView alloc] initWithNibName:nil bundle:nil];
// [self presentModalViewController:lastView animated:YES];
[self dismissModalViewControllerAnimated:YES];
}
My hunch is that you're throwing an exception because
MyMap *mapsView = [[MyMap alloc] initWithNibName:nil bundle:nil];
is failing to load a nib. Without seeing your console output it's impossible to say for sure. So a few things to try:
Comment out [self presentModalViewController:mapsView animated:YES];, see if it still crashes.
Explicitly name the nib you expect to load. The nib loader assumes the nib is named exactly the same as the view controller if you pass in nil. So if you don't have a match, you'll end up with an exception (Like this [[MyMap alloc] initWithNibName:#"NibNameWithoutExtension" bundle:nil];)
Set a breakpoint at [self present... and then hover your mouse over "mapsView" after execution pauses. If the popup thing shows you mapsView is nil, you know your trouble is trying to pass a nil object to -presentModalViewController:animated:. If your breakpoint never hits because you throw an exception first, well, there you go, the trouble is a line above.
edit:
One more thing. If your nib has a button that's wired to an action that no longer exists, that would definitely get you in trouble. Inspect each button and make sure no actions are labeled in yellow, indicating a mismatch between the button's target and the actions it's reporting to IB. This would definitely account for the breakpoint behavior you described.
here is my code , i am trying to get from one view to another without any memory leaks.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
firstviewcontroller *first = [[firstviewcontroller alloc] init];
[window addSubview:first.view];
[self.window makeKeyAndVisible];
return YES;
}
-(IBAction)gotosecondview:(id)sender
{
secondviewcontroller *second = [[secondviewcontroller alloc] init];
[self.view addSubview:second.view];
[second release];
}
-(IBAction)gotofirstview:(id)sender
{
[self.view removeFromSuperview];
}
to make the above code work without crashing , all i have to do is remove [second release].
if I remove it I get memory errors (build and analyze) . how can i solve this problem. and i dont want to use [self.navigationController pushViewController:second animated:YES];
all i am trying to do i navigating from one view to another and vice versa WITHOUT using navigation controller. my firstviewcontroller and secondviewcontroller are of type UIViewController.
Thanks in advance.
You need to keep the current view controller alive while its view is showing (so it can process the user input, etc.).
In your code, you can achieve that in several ways:
Keep an instance of firstviewcontroller and secondviewcontroller as instance variables, and release them on the dealloc method.
Keep an instance variable with the currently in use UIViewController and release it when you switch to another view.
The code for the second option would look something like this:
#interface
UIViewController *currentViewController;
#end
#implementation
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
firstviewcontroller *first = [[[firstviewcontroller alloc] init] autorelease];
[self switchToViewController:first];
[self.window makeKeyAndVisible];
return YES;
}
- (void)switchToViewController:(UIViewController *)aViewController {
[currentViewController.view removeFromSuperview];
[currentViewController release];
currentViewController = [aViewController retain];
[self.window addSubview:currentViewController.view];
}
-(IBAction)gotosecondview:(id)sender {
[self switchToViewController:[[[secondviewcontroller alloc] init] autorelease]];
}
#end
Here, all the logic for maintaining a single UIViewController alive lies in the switchToViewController method, which also handles the logic for switching from one view to another. As an added bonus, you can quickly add support for animations by adding a couple of lines in switchToViewController.
You can not release view in the call.
There is only one thing you can do in such conditions. use Autorelease,
The reason [second release] is crashing your code is likely because you're releasing your view controller which in turn releases the second view. The iPhone cookbook has some sample code on switching/swapping views if that's all that you're trying to accomplish. Here's the link. Hope this helps!
link text
I am very new to Obj-C and learning iphone development.
My question is how to add subview from app delegate.
Lets say I added subview called "MainView" from "applicationDidFinishLaunching" method.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
MainViewController *aViewController = [[MainViewController alloc] initWithNibName:#"MainView" bundle:nil];
self.mainViewController = aViewController;
[aViewController release];
[window addSubview:mainViewController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
}
"MainView.xib" file has a button to show its child view. When the button is clicked, it calls "showChildView" method.
- (IBAction)showChildView:(id)sender {
if (self.childViewController == nil) {
ChildViewController *childController = [[ChildViewController alloc] initWithNibName:#"ChildView" bundle:nil];
self.childViewController = childController;
[childController release];
}
[self.view insertSubview:childViewController.view atIndex:0];
}
From this code, when app launches, it shows "MainView" with a button. But when I clicked the button, the button is still visible as well as the content from the "ChildView.xib" file too.
How can I hide the "MainView" when I pressed the button and show only the contents of the "ChildView"?
Thanks for your help in advance.
well, you have to remove the original view first, before inserting the new subview, do it this way
- (IBAction)showChildView:(id)sender {
if (self.childViewController == nil) {
ChildViewController *childController = [[ChildViewController alloc] initWithNibName:#"ChildView" bundle:nil];
self.childViewController = childController;
[childController release];
}
[self.mainViewControlle.view removeFromSuperView];
[self.view insertSubview:childViewController.view atIndex:0];
}
Hope this helps.
You might want to check out the Utility App sample -- it demonstrates switching between two views with animation and adding/removing views from parent views.
you might want to create a navigation controller in the main view and than push the childviewcontroller onto it when invoking showChildView. You'll get the back navigation button for free that way