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
Related
I have page-based app. On each page I have 3 uibuttons at the top, uiscrollview with alphabet (uibuttons to sort data in uitable) at the right and uitableview at the center. How to show cell's detail view? If it is necessary to add uinavigationcontroller I can't do this. If I adds it, it disables interaction with my table, buttons and scrollview.
And another question is how to show new data in tableview and scrollview when goes to next page??
I have rootViewController class and DataViewController class.
rootViewController listing:
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#end
#implementation RootViewController
#synthesize pageViewController = _pageViewController;
#synthesize modelController = _modelController;
#synthesize navContr = _navContr;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
//[self presentModalViewController:navContr animated:YES];
self.pageViewController = [[[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil] autorelease];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.navContr = [[UINavigationController alloc] initWithRootViewController:self.pageViewController];
[self.view addSubview:self.navContr.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
for (UIGestureRecognizer *recognizer in self.pageViewController.gestureRecognizers){
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]){
[recognizer setEnabled:NO];
}
}
}
After few manipulations it works but I need help to get it work fine!
So now it looks like this
Next question: how do I remove the brown space at the top???
::UPDATE::
Problem solved. It needs just to set y-axis position of UINavigationController to -20 ;)
i'm not sure if this link about creating navigation-based project may help you.. (http://iosmadesimple.blogspot.com/2012/08/navigation-based-project-doing-it.html)
From that tutorial, there's a class called SampleViewController, subclass of UIViewController. You might want to put a tableView in SampleViewController.xib file. Then in your SampleViewController.h file, add an IBOutlet UITableView* yourTable property and synthesize it. Connect it to your tableView in your .xib file. //Or you may do it programmatically
in your SampleViewController.h, make your interface header look like this.. I think you already know this...
#interface SampleViewController:UIViewController < UITableviewDelegate, UITableViewDatasource >
in your SampleViewcontroller.m, under viewDidLoad method, set the table delegate and datasource to self:
yourTableView.delegate = self;
yourTableView.datasource = self;
Afterwhich, you implement tableView delegate and datasource methods... //you already know those since you were already able to show a tableview ;)
one of these methods is the "tableview:didSelectAtIndexpath:" --> this is the part wherein you can put your code when you click one of the cells.
Let's assume you have the DetailsViewController Class, this is the class you would like to show after clicking a cell and show its details.
DetailsViewController Class must have a variable that will accept the data you would like to show. Let's say, an NSString *detailsMessage; //do the #property and #synthesize thing...
Let's go back to SampleViewController.m file, under tableview:didSelectAtIndexpath: Method:
inside that Method.. put these codes.
DetailsViewController *detailsVC = [[DetailsViewController alloc] init];
detailsVC.detailsMessage = #"The Data you want to pass.";
[self.navigationController pushViewController:detailsVC animated:YES];
I hope this helps. :(
There may be other ways but by far the easiest way is to use a navigation controller. In fact, it is built to do exactly this.
If you don't want the navigationBar then you can hide it in the viewWillAppear function.
[self.navigationController setNavigationBarHidden:YES animated:YES];
Then you can add an other UIViewController to push when the user selects a cell.
Having read your OP again I'm not sure how you are adding your navigationController.
To use a navigationController you create it and load it at start time. You then create your current viewController (the one with the buttons and table etc...) and set this as the rootViewController of the navigationController.
Then you display the navigationController.
Could you explain how you are adding your navigationController as it may help understand what is going wrong.
Thanks
::EDIT::
OK, my assumption was correct.
The way you are using the navigation controller is not how it was intended.
OK, so at the moment your AppDelegate file will have a method Application didFinishLaunching...
It will look something like this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
You should change it so that it is like this...
first add a property to your appDelegate...
#property (nonatomic, strong) UINavigationController *navigationController;
Then change the didFinishLaunchingMethod to this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
This will still show you MainViewController but it will now be contained within a navigationController.
Next in your MainViewController function viewWillAppearAnimated add the line...
[self.navigationController setNavigationBarHidden:YES animated:animated];
This will then hide the navigationBar at the top of the view so you still have access to your buttons.
The you need a new ViewController and xib file (for example DetailViewController).
When the user selects a table row you need to then do something like...
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
//pass in details of which row was selected.
[self.navigationController pushViewController:detailView animated:YES];
This will then display your new view and new viewController. You will also need to write a way of passing the data in (set up a property on the DetailViewController).
Hope this helps.
I'm having trouble coding a button to go to the previous page. I was able to do it to go to the next page thinking if I did the same thing but changed it a bit it would work in reverse. Unfortunately, I come up with a lot of errors I can't resolve because it won't allow me to use the release function.
This is this the code that helps it to work going to the next page fine:
#import "ViewController.h"
#implementation ViewController
-(IBAction)btnClicked:(id) sender
{
//add the view of the view controller to the current View---
if (menuView==nil) {
menuView =
[[MenuView alloc] initWithNibName:#"MenuView"
bundle:nil];
}
[self.view addSubview:menuView.view];
}
-(void)dealloc {
[menuView release];
[super dealloc];
}
How do I do it so that a back button will go to the previous page though.
It's pretty simple, use this :
-(IBAction)back:(id) sender
{
[menuView.view removeFromSuperview];
}
But, I would suggest not using addSubview: for many views as it would be complex way to do. Use UINavigationController as #Paul.s suggested.
The way you are doing this is not quite correct and I would suggest doing some reading to get familiar with iOS programming.
Your program structure should be: create a navigation controller (2) to manage the stack of view controllers giving it a viewController (1) to act as it's root.
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// 1
FirstViewController *firstViewController = [[FirstViewController alloc] init];
// 2
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[firstViewController release]; firstViewController = nil;
self.window.rootViewController = navigationController;
[navigationController release]; navigationController = nil;
[self.window makeKeyAndVisible];
return YES;
}
This will display your first view controller inside a UINavigationController. A UINavigationController is responsible for managing a stack of UIViewController's and giving you UI to navigate back down the stack as well as calling all the appropriate presentation related methods on a UIViewController at the correct times e.g. viewDidLoad. You should check out The View Controller Programming Guide for lots of info
Then inside your first view controller you do something like this to respond to the button:
- (IBAction)buttonClicked:(id)sender;
{
SecondViewController *secondViewController = [[SecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release]; secondViewController = nil;
}
This creates a new view controller and pushes it onto the stack.
I'm trying to use a UINavigationController but I'm uncertain how. Up till now (for about a year), I've been using presentModalViewController and dismissModalViewController to present/dismiss view controllers.
So, this is what I did. My main view controller (the first one that shows on launch) is called MainViewController, and it extends UIViewController.
So I made this launch function in my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainViewController *controller = [[MainViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
And in my MainViewController's viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Title";
self.navigationController.navigationBar.tintColor = [Constants barColor];
....more code...
}
But, in my MainViewController, I'd like to present another view controller called SecondViewController, which needs a UINavigationBar with a back arrow button. So do I make SecondViewController extend UIViewController and do the same thing by setting the title and backButton in the viewDidLoad method? And how do I present it? What should I do to accomplish this?
You'll need to set a root view controller up, it's easiest starting from the apple template.
Here's where the magic happens:
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"MyNib" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
The nav controller does all the work for you (back buttons, titles, animations) - it keeps track!
My workflow is this:
Setup MutableArray in the viewDidLoad, add controllers to it, e.g:
NSMutableArray *array = [[NSMutableArray alloc] init];
MyCustomViewController *customView = [[MyCustomViewController alloc] initWithNibName:#"nib" bundle:#"nil"];
customView.title = #"Second Level";
[array addObject:customView];
self.controllers = array;
Then in your delegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UIViewController *childControllerToBe = [controllers objectAtIndex:row];
[self.navigationController pushViewController:childControllerToBe animated:YES];
}
This, along with a lot more can be learnt by reading a decent beginner book such as Beginning iPhone Development
Also, apple docs are always good :)
UINavigationController is a subclass of UIViewController, but unlike UIViewController it’s not usually meant for you to subclass. This is because navigation controller itself is rarely customized beyond the visuals of the nav bar. An instance of UINavigationController can be created either in code or in an XIB file with relative ease.
Please visit "How to add UINavigationController Programmatically"
You should Push it onto the navigation stack.
This Lecture by Stanford's iPhone Course will teach you a lot about Navigation Bars. (It's a quick read)
Basically at the heart of it you need this code:
[self.navigationController pushViewController:SecondView];
You can use PopViewController to go back programmatically, but the Back Button is automatically created.
Here's some source code from the Lecture. It covers exactly what you are having issues with.
I'm using the Kal calendar. For the code shown below I'm referring to the Holiday example. In this example the allocation and initialization of Kal is done in the applicationDidFinishLaunching in the AppDelegate. The UITableViewDelegate protocol (e.g. didSelectRowAtIndexPath) is also positioned in the AppDelegate class.
The AppDelegate:
#import "HolidayAppDelegate.h"
#import "HolidaySqliteDataSource.h"
#import "HolidaysDetailViewController.h"
## Heading ###import "Kal.h"
#implementation HolidayAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
kal = [[KalViewController alloc] init];
kal.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Today" style:UIBarButtonItemStyleBordered target:self action:#selector(showAndSelectToday)] autorelease];
kal.delegate = self;
dataSource = [[HolidaySqliteDataSource alloc] init];
kal.dataSource = dataSource;
// Setup the navigation stack and display it.
navController = [[UINavigationController alloc] initWithRootViewController:kal];
[window addSubview:navController.view];
[window makeKeyAndVisible];
}
// Action handler for the navigation bar's right bar button item.
- (void)showAndSelectToday
{
[kal showAndSelectDate:[NSDate date]];
}
#pragma mark UITableViewDelegate protocol conformance
// Display a details screen for the selected holiday/row.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Holiday *holiday = [dataSource holidayAtIndexPath:indexPath];
HolidaysDetailViewController *vc = [[[HolidaysDetailViewController alloc] initWithHoliday:holiday] autorelease];
[navController pushViewController:vc animated:YES];
}
#pragma mark -
- (void)dealloc
{
[kal release];
[dataSource release];
[window release];
[navController release];
[super dealloc];
}
#end
I don't want to put this into the AppDelegate, because there could be some overlapping code with other views. It should be a separate "component" which I can call and put on the stack.
In my navigation based project I have a main view, the RootViewController. From there I want to push the Kal view on the stack. Currently I'm pushing an additional ViewController on the stack. In the viewWillAppear method from this ViewController I do the things shown in the code above. The following problems appear:
Navigation back has to be done two times (one for the Kal calendar, one for my created view)
Navigation to my main view is not possible anymore
In the moment I don't know where to put this code. So the question is where to put the methods for allocation/initialization as well as the methods for the UITableViewDelegate protocol.
Solution:
if (kal == nil) {
kal = [[KalViewController alloc] init];
kal.navigationItem.title = NSLocalizedString(#"Timetable",#"");
kal.delegate = self;
self.dataSource = [[[MyDataSource alloc] init] autorelease];
kal.dataSource = dataSource;
}
[[self navigationController] pushViewController:kal animated:YES];
I've done the initialization in my RootViewController. This isn't the best solution, but I didn't found another one.
Suggest to read the SimpleEKDemo example from Apple.
It seems like all of the Cocoa Touch templates are set up to load a nib.
If I want to start a new project that's going to use a view controller, and load its view(hierarchy) programatically, not from a nib/xib, what are the steps to setting that up or adjusting a template.
I though all I had to do was implement -loadView, but I have trouble every time I try to do this.
It's reasonably simple to do completely programmatic user interface generation. First, you need to edit main.m to look something like the following:
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
UIApplicationMain(argc, argv, nil, #"MyAppDelegate");
[pool release];
return 0;
}
where MyAppDelegate is the name of your application delegate class. This means that an instance of MyAppDelegate will be created on launch, something that is normally handled by the main Nib file for the application.
Within MyAppDelegate, implement your applicationDidFinishLaunching: method similar to the following:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
if (!window)
{
[self release];
return;
}
window.backgroundColor = [UIColor whiteColor];
rootController = [[MyRootViewController alloc] init];
[window addSubview:rootController.view];
[window makeKeyAndVisible];
[window layoutSubviews];
}
where MyRootViewController is the view controller for the primary view in your window. This should initialize the main window, and add the view managed by MyRootViewController to it. rootController is kept as an instance variable within the delegate, for later reference.
This should let you programmatically generate your user interface through MyRootViewController.
UIViews themselves do not have a hierarchy, UINavigationControllers do. So init one of those, and pop a UIViewController onto it's stack. This should do it, in the most basic way possible, with no XIB files at all. You should be able to build on this.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
UINavigationController *navController = [[UINavigationController alloc] init];
UIViewController *viewController = [[UIViewController alloc] init];
// set the properties of viewController here, to make it look like you want
[navController pushViewController:viewController animated:NO];
[window addSubview:navController.view];
// Don't forget memory management
[navController release];
[viewController release];
[window makeKeyAndVisible];
}