I have a view-based application with three xib files, each with its own view controllers. How do I change from one to another? I use this to move from xib 1 to xib 2, but when I use the same code to move from xib 2 to xib 1, i get a EXC_BAD_ACCESS on the [self presentModal....] line.
MapView *controller = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
How can I freely move from one xib to another?
What I think you are trying to do is is present a modal view and then dismiss it, right? If that is the case then you put the code below in the method that you use to dismiss it(e.g. -(IBAction)dissmissModalView)
[self.parentViewController dismissModalViewControllerAnimated:YES];
Hopefully that works. Let me know.
initWithNibName isn't really necessary... you can change that to nil.
So, here is the correct code (without animation):
MapView *mapView = [[MapView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:mapView animated:NO];
You should not be receiving EXC_BAD_ACCESS when trying to go back to view 1 using present. If you cannot resolve it, just use this instead:
[self dismissModalViewControllerAnimated:YES];
The second view controller will disappear and the first view controller will be visible again.
Note that presenting modal view controllers like the other answers here will mean that you have an ever-accumulating stack of view controllers. Use the application long enough and it will crash.
Instead, you can swap out the view from the application's window. Here's one way of doing that:
Add a data member to your app delegate to store the current view:
#class MyAppDelegate : NSObject <...>
{
UIViewController* currentVC;
}
and add a message there to swap VCs:
-(void)setCurrentVC:(UIViewController*)newVC
{
if (newVC==currentVC) return;
if (currentVC!=nil)
[currentVC.view removeFromSuperview];
currentVC = newVC;
if (newVC!=nil)
[self.window addSubview:newVC.view];
}
and to swap from one screen to another:
MapView* mapView = [[MapView alloc] init];
[[[UIApplication shared] delegate] setCurrentVC:mapView];
Related
I'm calling this method when trying to present a new view controller. The commented out lines are the other things I've tried with no success.
-(void)presentMailBoxViewController{
TPMailBoxViewController* mailBoxViewController=[[TPMailBoxViewController alloc]initWithNibName:#"TPMailBoxViewController" bundle:nil];
[self.navigationController pushViewController:mailBoxViewController animated:YES];
//[self.navigationController presentViewController:mailBoxViewController animated:YES completion:NULL];
//[self presentViewController:mailBoxViewController animated:YES completion:NULL];
}
I've set the file owner as my corresponding view controller.
I've even linked the view object of my xib into my view controller as a property.
But, when I break on [self.navigationController pushViewController:mailBoxViewController animated:YES];
The view property of the view controller is nil. What gives?
"UIViewController" already has a "view" property, so you don't need "myView".
Open up your storyboard or XIB file and make certain that the "view" that you want to be displayed with your is connected in your storyboard or XIB file to your TPMailBoxViewController object.
Right after you "initWithNibName", the view controller object exists but its "view" property is likely to be nil because the view has not been loaded yet.
It's when you push the view controller, that is when your "TPMailBoxViewController" will get the "viewWillLoad" and "viewWillAppear" methods being called and when the view is loaded, the "view" outlet will change from nil to something real.
A project clean and this one line change in my presentMailBoxViewController fixed my issue. Still would like to know why though. Thanks everyone!
-(void)presentMailBoxViewController{
TPMailBoxViewController* mailBoxViewController=[[TPMailBoxViewController alloc]initWithNibName:#"TPMailBoxViewController" bundle:nil];
[self presentViewController:mailBoxViewController animated:YES completion:NULL];
}
In your AppDelegate, you need to set the root object of the window as the navigation controller. You can do it like this:-
YourViewController *rootObj = [[LoginViewController alloc] init];
UINavigationController *navObj = [[UINavigationController alloc] initWithRootViewController:rootObj];
[self.window setRootViewController:navObj];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
After this, try pushing the viewcontroller, it should work
I'm developing a single view iOS 5.0+ app and I'm going to navigate throw my ViewControllers this way:
SearchViewController* search =
[[SearchViewController alloc] initWithNibName:#"SearchViewController"
bundle:nil];
[self presentViewController:search
animated:NO
completion:nil];
My question is, if I'm opening SearchViewController from HomeViewController, is HomeViewController dismissed after SearchViewController is shown?
I have a lot of UIViewControllers and I don't know if all of them will be on memory while user is navigating between them.
If You want to Present Only one Viewcontroller you can try like,
SearchViewController* search =
[[SearchViewController alloc] initWithNibName:#"SearchViewController"
bundle:nil];
[self dismissViewControllerAnimated:NO completion:^{
[self presentViewController:search
animated:NO
completion:nil];
}];
When you present a ViewController from another ViewController, they never get released from memory. To release them from memory you need to explicitly dismiss them.
The method presentViewController:animated:completion: sets the
presentedViewController property to the specified view controller,
resizes that view controller’s view and then adds the view to the view
hierarchy.
So you see you are getting a stack of ViewControllers and adding a View on top of another.
I am trying to figure out for a while now, how should I use the annotation button to switch
to another mapView. The app I am working on uses MapBox - maps. I checked the exemples
provided by them, but programmatically switching between two maps is there always achieved
through tab bar (which is not the case I want to use).
I am working with storyboards and I understood it quit well, how the segue should be made
in the Interface builder, but I think I am not managing with the programmatically integrated
buttons on map views. I initiated 'id's in both header files and I proclaimed them in the
Identity Inspector as well.
This is the part of the code, where I implement the RMMMapView with the annotation in the
main View Controller - ViewController and it works perfectly:
- (void)viewDidLoad{
[super viewDidLoad];
RMMapBoxSource *onlineSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:onlineSource];
_mapView.tileSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView.centerCoordinate = CLLocationCoordinate2DMake(0,0);
_mapView.adjustTilesForRetinaDisplay = YES;
_mapView.zoom = 4;
_mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:_mapView];
_mapView.showsUserLocation = YES;
[_mapView setConstraintsSouthWest:[_mapView.tileSource latitudeLongitudeBoundingBox].southWest
northEast:[_mapView.tileSource latitudeLongitudeBoundingBox].northEast];
RMPointAnnotation *annotation = [[RMPointAnnotation alloc] initWithMapView:_mapView
coordinate:_mapView.centerCoordinate andTitle:#"Hello, world!"];
[_mapView addAnnotation:annotation];
}
and this is the part, where I try to call the LowContentMap viewController, from the ViewController - main ViewController:
- (void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender {
if ([segue.identifier isEqualToString:#"Hello, world!"]) {
//LowContentMap *lowContentMap = segue.destinationViewController;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
LowContentMap *lowContentMap = [storyboard instantiateViewControllerWithIdentifier:#"lowContentMap"];
lowContentMap.lcm = _vc;
}}
This is the part of the code, that should be filled in:
- (void)mapView:(RMMapView *)mapView annotationView:(RMPointAnnotation *)annotation calloutAccessoryControlTapped:(UIControl *)control{
[self performSegueWithIdentifier:#"ShowSomeViewController" sender:annotation];
}
It would be really great, if somebody would try to resolve the problem.
I followed the discusion between Noa and Kronos at:
Setting up a detail view controller using a segue
but I still think, the part with the 'id' is something I am doing wrong. Thanks in advance.
1. I think your problem is that you don't know how to display another viewController
You should give the "View Controller Programming Guide" a good read, especially the part "Presenting View Controllers from Other View Controllers"
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
I also recommend to check out some of the awesome WWDC videos that show how to use ViewControllers.
2. How to create and display a viewController
There are many ways to do it. E.g. using the storyboard to create and display the viewController, define a protocol in the child controller, override "performSegueWithIdentifier" to set the delegate and implement the protocol to dismiss the vc.
However, in your case, it seems to make sense to do it all programmatically. Thus, you need to:
a) find the right place to add your action
b) alloc and init your view controller:
MyController *myController = [[MyController alloc] init];
// setup as required, there should be at least a delegate (being able to dismiss the view)
myController.delegate = self;
If you have designed your viewController in a storyboard, you might want to use this alloc/init routine instead:
MyController *myController = [[UIStoryboard storyboardWithName:#"Main.storyboard" bundle:nil] instantiateViewControllerWithIdentifier:#"MyController"];
myController.delegate = self;
c) display your new view controller;
this depends on if you have a navigationController:
[self.navigationController pushViewController:myController animated:YES];
...or if you want to present it modally:
[self presentViewController:myController animated:YES completion:NULL];
d) dismiss when done;
when your other controller is done with whatever it does, it should inform its delegate (implement your own protocol!) that it's done and should be dismissed. The delegate is the original viewController that created (alloc'd/inited) the "myController":
// this method should be defined in a protocol and implemented in the vc that created (and owns) the child view controller
// typically, this is the parent view controller
- (void)done {
[self dismissViewControllerAnimated:YES completion:NULL];
}
if you used a navigationController it's not -dismissViewControllerAnimated:, but
[self.navigationController popViewControllerAnimated:YES];
hope this helps to clarify things
I use the following code to switch from main view (ViewController.h)to another view (TouchViewController) and then similarly switch from this view to the next view (QuestionsViewController).
How do I go back to the main view from here? i.e what is the value for initWithNibName for MainStoryboard.storyboard?
- (IBAction)startGame:(UIButton *)sender {
TouchViewController *second = [[TouchViewController alloc] initWithNibName:#"TouchViewController" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
and
- (IBAction)selectTopic:(UIButton *)sender {
NSString *category = [[sender titleLabel] text];
[[NSUserDefaults standardUserDefaults] setObject:category forKey:#"MyKey"];
QuestionsViewController *second = [[QuestionsViewController alloc] initWithNibName:#"QuestionsViewController" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
Now to go back to the main view i have a problem i.e
- (IBAction)backtoMainMenu:(id)sender {
ViewController *second = [[ViewController alloc]initWithNibName:#"MainStoryboard.storyboard" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
At this point the app just crashes! I suppose it's because initWithNibName:#"MainStoryboard.storyboard" can't be used but the ViewController does not have any other xib file - so what do I do?
First of all storyboard can't be used as a xib file they are not the same thing. Second you have one view controller that presents a view controller that also present a view controller so what you can do is something like this from the third view controller:
[self.presentingViewController.presentingViewController
void)dismissViewControllerAnimated:YES completion:nil];
This is the fastest way you can do it, but it's not really reusable, if you have a more complex view controller hierarchy than it will be really ugly to do it like this, other solutions can be delgates or notifications.
Also just a piece of advice, when you want to go back to a previous screen in general you don't what to create a new view controller (as you try in backToMainMenu method, you simply want to remove all the view controllers (screens) until you reach the desired screen.
I am working on an iPhone app but found that I require another view / window to get the user to input and save data / information there.
How do I add another view? Do I add it in interface builder and then link it in the main app delegate or will it have its own .h and .m files.
I selected a window view app to start with, do I need to start over with a flip side view app or can this just be added in anyway if I have the correct code there.
manny thanks
Carl
The Window app is perfect for you. In your AppDelegate file, you should have a section like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
// Configure and show the window
[window addSubview:[yourViewController view]];
[window makeKeyAndVisible];
}
This is the part of the code that declares, allocates and adds your custom view to the window. You have a couple choices for how to add the second view. You can either add it in place of this one, or add it after this one using a Navigation Controller. To add the navigation controller, change the above method to look like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
UINavigationController *yourViewControllerWrapper = [[UINavigationController alloc] initWithRootViewController: yourViewController];
// Configure and show the window
[window addSubview:[yourViewControllerWrapper view]];
[window makeKeyAndVisible];
}
There, we create your custom view, then wrap it in a navigation controller. The navigation controller is what gets added to the window. Next the code to switch to the second view would look like this, assuming you switch views on a button press:
-(IBAction)switchViewController{
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController];
}
Of course, you should replace the line
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
with the proper way of instantiating your second view controller. This could be from a nib file like above, or programmatically.
As far as creating the view files, you should create a nib in Interface builder for the layout of everything, then create a .h and .m file for the ViewController code itself.
you can also display new frame instead of new view. It is easier sometimes, as you don;t have to pass parameters - you are in one class:
CGRect frame = okresView.frame;
frame.origin.x = frame.size.width;
if ( [okresView superview] == nil )
{
[self.view addSubview:okresView];
}
okresView.frame = frame;
[okresDataTableView reloadData]; // przeładowanie tabeli na subwidoku
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5];
frame.origin.x = 0;
okresView.frame = frame;
[UIView commitAnimations];
if you want new subview, you can use a few methods - just download few applications from XCode help and check how they do this. Nice example are in 'Elements' and 'UICatalog' application where you have flipped view and other examples.
// Create and push another view controller.
UIViewController *myViewController = [[UIViewController alloc] init];
myViewController.title = #"My First View";
myViewController.view.backgroundColor = [UIColor redColor];
//to push the UIView.
[self.navigationController pushViewController:myViewController animated:YES];