I am new to iOS development and I am doing little project as a research.
I have an app where after I start it I am showing MainViewController, but if this is the first launch of this app I want to show Sub1ViewController (names are made up) using presentViewController method called in MainViewController.
After user puts in some data on Sub1ViewController I invoke dismissViewController method to hide it.
The hard part starts here - I have no idea how to capture the event when Sub1ViewController is dismissed and I can present Sub2ViewController also using presentViewController invoked from MainViewController. All the time I am getting messages that I am trying to present view when another present or dismiss is in progress.
PS: I am using Xamarin, but I also understand objective-c.
hi you can try out this
[self dismissViewControllerAnimated:YES completion:^{
//code to be executed with the dismissal is completed
// for example, presenting a vc or performing a segue
}];
you can write code after completion of dismiss one view controller
or
You can achieve this by present view after some delay in dismiss method
-(void)onDismisViewController{
[self performSelector:#selector(presentSecoundViecontoller) withObject:self afterDelay:1];
}
-(void)presentSecoundViecontoller
{
SecoundViewController *secoundVC = [[SecoundViewController alloc] initWithNibName:#"secoundVC" bundle:nil];
[self.navigationController presentViewController:secoundVC animated:YES completion:NULL];
}
EDIT
Try this i Try and it work
crate one delegate Method in subviewcontroller1 and set delegate in mainviewcontroller and implement method in mainvie and present subviewcontroller2 in this delegate method its work
try this if not let me know will post code.
Delegate Creation on subviewcontroller1.h file
#protocol st1Protocol <NSObject>
- (void)presentViewController;
#end
#interface SubViewController1 : UIViewController
#property (nonatomic,assign) id <st1Protocol> delegate;
- (IBAction)dissmiss:(id)sender;
SubViewcontroller1.m file
i put dismiss view on button click of subviewcontroller1 you do this in you dismiss method
- (IBAction)dissmiss:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
//code to be executed with the dismissal is completed
// for example, presenting a vc or performing a segue
[self.delegate presentViewController];
}];
}
now implementation of this delegate method in main view controller.
implement delegate method in .h file
#interface StViewController : UIViewController<st1Protocol>
set delegate in mainviewcontroller.m file view didload
- (void)viewDidLoad
{
[super viewDidLoad];
subViewcontroller1 *st1=[[subViewcontroller1 alloc]initWithNibName:#"subViewcontroller1" bundle:nil];
st1.delegate=self;
[self presentViewController:st1 animated:YES completion:nil];
// Do any additional setup after loading the view from its nib.
}
delegate method implementation in main view controller
-(void)presentViewController{
SubmViewcontroller2 *st2=[[SubmViewcontroller2 alloc]initWithNibName:#"St2ViewController" bundle:nil];
[self presentViewController:st2 animated:YES completion:nil];
}
hope this may help you happy coding.
Related
New to iOS development & Objective-C and am a little unsure how to go about solving this issue.
I'm working on a project that works like a video player. There are two ViewControllers:
MenuViewController (has a list of titles that act as buttons)
PlayerViewController (view where video plays)
In the MenuViewController, I want to be able to click onto a button (video title) :
- (IBAction)videoOne:(id)sender
{
PlayerViewController * vc = [[PlayerViewController alloc] initWithNibName:#"PlayerViewController" bundle:nil];
[self presentModalViewController:vc animated:YES];
}
and have an action that's currently defined in the PlayerViewController automatically execute as soon as its loaded.
Is there a way to have a button in one ViewController call the action in another ViewController as soon as that second ViewController has loaded?
Thanks!
The right way to solve this problem will be set up a delegate pattern between the two view-controllers.
Example:
#protocol PlayerViewControllerDelegate<NSObject>
{
-(void)playerViewControllerViewDidLoad:(PlayerViewController *)playerVC;
}
Then, in PlayerViewController.h create a weak delegate variable:
#property (nonatomic, weak) id<PlayerViewControllerDelegate> delegate;
In PlayerViewController.m, notify the delegate on viewDidLoad:
-(void)viewDidLoad {
[super viewDidLoad];
[self.delegate playerViewControllerViewDidLoad:self]
}
In MenuViewController:
- (IBAction)videoOne:(id)sender
{
PlayerViewController * vc = [[PlayerViewController alloc] initWithNibName:#"PlayerViewController" bundle:nil];
vc.delegate = self
[self presentViewController:vc animated:YES];
}
Finally, implement the protocol in MenuViewController, and you're ready to go:
#interface MenuViewController : UIViewController<PlayerViewControllerDelegate>
#end
#implementation MenuViewController
-(void)playerViewControllerViewDidLoad:(PlayerViewController*)playerVC
{
[playerVC playVideo];
}
#end
It is usually not good practice to have one controller controlling the behavior of another. Instead, you can have the MenuViewController create the PlayerViewController and set variables so the new player knows how to behave based on its internal state.
There are several UIViewController methods that you can override in order to perform actions during the controller's lifecycle. Based on your question it seems like you want the viewDidLoad method.
I am not sure how you are passing videos between controllers, but if you were using URLs (to Youtube videos for example) then you could do something like the following:
// MenuViewController.m
- (IBAction)videoOne:(id)sender {
PlayerViewController* vc = [[PlayerViewController alloc] initWithNibName:#"PlayerViewController" bundle:nil];
// Pass any necessary data to the controller before displaying it
vc.videoURL = [self getURLForSender:sender];
[self presentViewController:vc animated:YES completion:nil];
}
// PlayerViewController.m
- (void)viewDidAppear {
// View did appear will only be called after the controller has displayed
// its primary view as well as any views defined in your storyboard or
// xib. You can safely assume that your views are visible at this point.
[super viewDidAppear];
if (self.videoURL) {
[self playVideo];
}
}
You would need to define the property videoURL on PlayerViewController and expose it publicly. If you are using local files (such as from the user's photo storage) you could pass the video to the new view controller before presenting it.
There are other UIViewController lifecycle methods that you can override. They are explained in more depth in this post as well as Apple's UIViewController Documentation.
Edit: changed presentModalViewController:animated: to presentViewController:animated:completion: and changed viewDidLoad to viewDidAppear as it seems more appropriate for the question.
presentModalViewController:animated: is deprecated. Use presentViewController:animated:completion: instead.
In the completion Block, you can call a method on the presented view controller:
[self presentViewController:otherVC
animated:YES
completion:^{ [otherVC startPlaying]; }];
The completion is run after the presented controller's viewDidAppear.
I have a main view controller that is able to process gestures in an iPad app.
I launch a second view controller via:
wVC = [self.storyboard instantiateViewControllerWithIdentifier:#"vc_webView"];
[self presentViewController:wVC animated:YES completion:nil];
If I now gesture while that VC is showing, the gestures are not processed. How can I "pass" the gestures to the first storyboard for subsequent processing so that I don't need to rewrite the whole gesture functionality in the new VC?
OK so the answer is to use delegates.
For completion's sake, here is the way to do it:
Set up the first VC to be a delegate of the second, then in the second VC call the delegate function.
In original controller right before presenting the wVC:
wVC.delegate = self;
In the wVC.h file:
#protocol senddataProtocol <NSObject>
-(void)ProcessPasswordGesture:(NSInteger)iGest;
#end
#property(nonatomic,assign)id delegate;
In the wVC.m file:
#synthesize delegate;
[delegate ProcessPasswordGesture:<data>];
Hope this helps someone else!!
I'm new to iOS programming and I'm facing a problem
I'm having a problem with custom delegate.
I'm trying to make a simple custom where it return data to the previous view controller and pop the current view controller.
I have 2 navigation view controller
1 - main view controller
2 - Adding
and here is the protocol that is written in the adding view controller
#protocol AddingDelegate <NSObject>
#required
-(void)setInformation:(Adding *)controller withObject:(Conference *)info;
and here is the where I called it in adding view controller
-(IBAction)addingConference
{
NSLog(#"Adding Button Pressed");
conferenceObject = [[Conference alloc]init];
conferenceObject.name = [NameTX text];
conferenceObject.city = [CityTX text];
conferenceObject.description = [Dectription text];
NSMutableArray *info = [[NSMutableArray alloc] init];
[info addObject:conferenceObject];
[self.delegate setInformation:self withObject:conferenceObject];
NSLog(#"adding Conference method is done");
}
I wrote the delegate at the interface in the main view controller
#interface MainViewController : UITableViewController <AddingDelegate>
#end
and here where I declared the delegate method
-(void)setInformation:(Adding *)controller withArray:(NSMutableArray *)info
{
NSLog(#"in the main view at the delegate");
[self.navigationController popToRootViewControllerAnimated:YES];
NSLog(#"Should be popped right now");
}
and this is the prepare for segue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddObject"]) {
UINavigationController *navigation = segue.destinationViewController;
Adding *addingViewController = [[navigation viewControllers]objectAtIndex:0];
addingViewController.delegate = self;
}
}
now the problem is when I push the adding on top of the stack and then fill the information and press done the adding view controller doesn't pop to show main view controller.
I tried to log everything and the logs from the main view controller doesn't show .
Please help me
What I notice here is that in the implementation of prepareForSegue:sender: the segue's destinationViewController is a navigation controller. This makes me think that your segue is not pushing the AddingController on the current navigation stack but it's presenting a new one instead. This means the new navigation controller containing the AddingController is presented modally and as such, when you try to pop the navigation stack nothing seems to happen because you're operating on the wrong navigation stack. If that is the case you have two options: 1. change [self.navigationController popToRootViewControllerAnimated:YES]; for [self dismissViewControllerAnimated:YES completion:nil]; or 2. change the segue to be a push segue instead of a modal segue and point the segue directly to the AddingController.
In Adding.m
#class Adding;
#protocol AddingDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface Adding : UIViewController
#property (weak, nonatomic) id <AddingDelegate> delegate; // have you forgot this one
#end
and use
[self dismissViewControllerAnimated:YES completion:nil];
You need dismiss if you want get back to previous screen and make sure you have added Navigation controller
I have a HomeView and a HomeDropDownView.
HomeDropDownView is shown as a drop-down view over the HomeView.
HomeView is a delegate of HomeDropDownView.
When I do an action in HomeDropDownView I want to call a delegate method in HomeView and have that delegate method present a third view controller, TestViewController from it's navigation controller.
If I try to launch TestViewController from anywhere in the class it works fine - except from the delegate method.
There are animations in HomeDropDownView but putting the call to the delegate method in the complition does not make the view controller appear. And in the case that I'm using this the animation's don't fire anyway; there's only a resizing without animation.
TestViewController's init does get called as well as the viewDidLoad but not the viewWillAppear and the view dose not appear.
Code:
HomeDropDownView
- (void)finalAction {
...
[self callDelegateAction];
...
- (void)calldelegateAction {
if ([self.delegate respondsToSelector:#selector(launchTestView)] ) {
[self.delegate launchTestView];
} else {
DLog(#"Error out to the user.");
}
}
HomeView
- (void)launchTestView {
//[self listSubviewsOfView:self.parentViewController.view];
NSLog(#"delegate method | self: %#", self);
TestViewController *tvc = [[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
//[self.navigationController presentViewController:tvc animated:YES completion:nil];
//[self.view.window.rootViewController presentViewController:tvc animated:YES completion:nil];
//[self.navigationController pushViewController:tvc animated:YES];
AppDelegate *appdelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appdelegate.tabBarController.navigationController presentViewController:tvc animated:YES completion:^() {
NSLog(#"Done!");
}];
}
None of the above approaches work. But if I put the exact same code into the viewDidAppear or put it in a button action method, it will work fine. At the time of calling the delegate method's self is HomeView and all the subviews, including the nav controller do seem to be there. This is in a tabcontroller-based project but I think that any of the above are acceptable ways to call the nav controller still.
What am I missing? Why does my delegate method not want to push/present a viewcontroller on HomeView's Nav controller? It's probably something I'm missing but I can't find a reason in the Apple Docs or any other thread.
Thanks for the help!
Sadly this turned out to be that HomeView was being changed underneath the execution of the message. So by the time the HomeView got the message call it was no longer the same HomeView object that had requested action in the first place. So it was not the same delegate.
This was done so that it would appear to the user that the same view was being used for different things.
But this is a good example of why you should not destroy and re-create critical views. We should have been using the same view and reloading the objects instead if we knew that we would be sending messages. Or had some notion of a control structure.
My app have a main screen (mainView). On mainView, I have a button. When user taps it, I use
[self presentViewController:libraryView animated:YES completion:nil]
to present another view (libraryView). Then, on libraryView, I use
[self.view addSubview:tabBarController.view]
to add a UITabBarController which has 2 View Controllers: featuredBooks and recentBooks
Everything works fine. But when I add a button to featureBooks to dissmiss the libraryView and return to mainView, the following methods don't work
[self dismissViewControllerAnimated: YES completion:nil]
[self.parentViewController dismissViewControllerAnimated: YES completion:nil]
[self.presentingViewController dismissViewControllerAnimated: YES completion:nil]
I know the reason: self refers to featureBooks's view, not libraryView.
So, how do I refer to libraryView, dismiss it and return to mainView from a view controller (featureBooks or recentBooks) inside Tab Bar Controller?
Thank you very much.
Make mainView delegate object of libraryView... Then when you call the delegate method from libraryView, mainView will call in its code the method dismissViewcController.
So:
1)create into libraryView controller .h code:
#protocol LibraryViewDelegate
- (void) LibraryViewDelegate_DismissButtonClicked;
#end
2)then create a property into mainView .h file:
#property(nonatomic, assign) NSObject<LibraryViewDelegate> *delegate;
and the following into the .m one
#synthesize delegate;
and assign mainView to this property after libraryView object creation and before you will present it
3)write the following code into the mainview .m file:
-(void)LibraryViewDelegate_DismissButtonClicked{
//put here the code for dismissing mainView created modalViewController (libraryView)
}
4)then write the code that call:
[self.delegate LibraryViewDelegate_DismissButtonClicked];
into libraryView when you press the dismiss button