What notification do I get when a view appears in iphone? - iphone

I want to know what notification would I get in my CustomView class when this view will be displayed on screen.
CustomView *customView = [[CustomView alloc] init];
[self.view addSubview:customView];
NewViewController *newController = [[NewViewController alloc] init];
[self.navigationController pushViewController:newController animated:YES];
and after some work I pop this viewController.
[self.navigationController popViewControllerAnimated:YES];
I want to know what method in CustomView class will be called when that view will appear again on the screen.
Actually I have an infinite loop animation in that CustomView and on pushing to nextController I have to stop that animation loop and after coming back I need to start it again.

UIView doesn't get
viewWillAppear
viewDidDisappear
etc
ViewController in which it's contained, however, does, so, in order to pass it to UIView you are to implement following method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self.view.subviews objectAtIndex:0] viewWIllAppear]; // i assume your subview is the only one, otherwise you need to know the index, or have it as an ivar/property
}
Another idea - since you use your view a lot, i assume you do not recreate it. Let it be a property of your [[UIApplication sharedApplication] delegate]. Now you can access it like this:
#define SharedView [(appDelegate*)[[UIApplication sharedApplication] delegate] sharedView];
Then make custom UIViewController and overwrite viewWillAppear:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ( [SharedView.superview isEqual:self.view] )
{
[SharedView viewWillAppear];
}
}

You answered it yourself.
viewWillAppear

Have you looked at: UIView
Observing View-Related Changes
– didAddSubview:
– willRemoveSubview:
– willMoveToSuperview:
– didMoveToSuperview
– willMoveToWindow:
– didMoveToWindow

Related

iOS: Dismissing and Presenting ModalViewController without access to its Parent ViewController

Background: I would like to dismiss a modalView that I have presented earlier and right away present the same viewController that I just dismissed with new information.
Problem: I have not been very successful in doing so without an explicit pointer to the parent ViewController that presented the first ViewController modally. I am trying to write this class that works without messing around with the previous viewController's code.
Possible lead: There are couple of things I have been experimenting with:
1.) Trying to get access to the parent ViewController, which at this time I don't know how to.
2.) Once access to the parent is gained, I can simply apply the following code:
UIViewController* toPresentViewController = [[UIViewController alloc] init];
[self dismissViewControllerAnimated:YES completion:^{
[parentViewControllerAccessor presentModalViewController:toPresentViewController animated:YES];
}];
In theory this should work given the access to parent viewController. I am open to other ways of doing this.
Assumption: You do not have permission to change any code in the parent ViewController.
Your code looks like it should work. If you are using iOS 5 there is a UIViewController property called presentingViewController.
#property(nonatomic, readonly) UIViewController *presentingViewController;
So you can use this property to get the view controller that presented your modal controller.
Note: In iOS 4 parentViewController would be set to the presenting controller, so if you are supporting both iOS 4 and 5 you will have to check the OS version first to decide which property to access. In iOS 5 Apple have fixed this so that parentViewController is now exclusively used for the parent of contained view controllers (see the section on Implementing a Container View Controller in the UIViewController documentation).
Edit: Regarding accessing self.presentingViewController from within the block: By the time the block is called (after the modal view controller is dismissed) the presentingViewController property may get set to nil. Remember that self.presentingViewController inside the block gives the value of the property when the block is executed, not when it was created. To protect against this do the following:
UIViewController* toPresentViewController = [[UIViewController alloc] init];
UIViewController* presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^
{
[presentingViewController presentModalViewController:toPresentViewController animated:YES];
}];
This is necessary not because self is gone/dismissed (it is safely retained by the block), but because it is no longer presented, therefore its presentingViewController is now nil. It is not necessary to store the presentingViewController anywhere else, the local variable is fine because it will be retained by the block.
You could accomplish this using notifications.
For example, fire this notification from outside the modal view when you want it to be dismissed:
[[NSNotificationCenter defaultCenter] postNotificationName:#"dismissModalView"
object:nil
userInfo:nil];
And then handle that notification inside your modal view:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(dismissMe:)
name:#"dismissModalView"
object:nil];
}
- (void)dismissMe:(NSNotification)notification {
// dismiss it here.
}
the solution for ios5:
-(void)didDismissModalView:(id)sender {
// Dismiss the modal view controller
int sold=0;
if(sold==0){
//Cash_sold.delegate = self;
// Cash_sold.user_amount.text=[NSString stringWithFormat:#"%d",somme];
Cash_sold = [[CashSoldview alloc] initWithNibName:#"CashSoldview" bundle:nil];
CGRect fram1 = CGRectMake(200,20,400,400);
Cash_sold.view.superview.frame = fram1;
Cash_sold.view.frame=fram1;
Cash_sold.modalTransitionStyle= UIModalTransitionStyleCoverVertical;
Cash_sold.modalPresentationStyle=UIModalPresentationFormSheet;
UIViewController* presentingViewController = self.parentViewController;
[self dismissViewControllerAnimated:YES completion:^
{
[presentingViewController presentModalViewController:Cash_sold animated:YES];
}];
}
}
Try the following code:
[self dismissViewControllerAnimated:NO
completion:^{
// instantiate and initialize the new controller
MyViewController *newViewController = [[MyViewController alloc] init];
[[self presentingViewController] presentViewController:newViewController
animated:NO
completion:nil];
}];

Why my presentModalViewController method doesn't work

I created a UIImagePickerController in the viewDidLoad method in my rootViewController.
- (void)viewDidLoad {
[super viewDidLoad];
UIImagePickerController *pickerController=[[UIImagePickerController alloc] init];
pickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
pickerController.delegate=self;
[self presentModalViewController:pickerController animated:YES];
[pickerController release];
}
But the view of UIImagePickerViewController didn't appear on the screen.
The SDK version is 4.3
Is there some mistakes i make?
Thanks!
viewDidLoad is called after the view has been loaded and before the view is displayed. viewDidAppear: is called when the view is onscreen and is the correct point to present a modal view controller.
And if you want to do it only once, you might want to consider using a BOOL to keep track of it.

In iPhone development how to access a method in the ParentViewController

I am a newbie iPhone Programmer and have a question regarding how to access methods of a Parent View Controller.
In my program when the program first loads (applicationDidFinishLaunching) I do the following code:
[window addSubview:rootViewController.view];
[window makeKeyAndVisible];
which basically calls this
- (void)viewDidLoad {
HomeViewController *homeController=[[HomeViewController alloc] initWithNibName:#"HomeView" bundle:nil];
self.homeViewController=homeController;
[self.view insertSubview:homeController.view atIndex:0];
[homeController release];
[super viewDidLoad];
}
Now, I have an IBAction call on HomeViewController that I want to have it call a method in root View Controller
I want to call this method
- (void)loadNewGame
{
self.questionViewController = [[QuestionViewController alloc] initWithNibName:#"QuestionView" bundle:nil];
//[homeViewController.view removeFromSuperview];
[self.view insertSubview:questionViewController.view atIndex:0];
}
So my question is how do I call a method from the Parent View controller?
I've tried
[self.view removeFromSuperview];
[self.parentViewController loadNewGame];
but that doesn't seem to work. Could someone please ploint me in the right direction.
Thanks in advance
Scott
First off, typically you call [super viewDidLoad] first in your viewDidLoad.
You will have to have an instance variable in your homeController class for your rootViewController. Then you could have a method in homeController:
- (void) loadNewGame
{
[self.rootViewController loadNewGame];
}
This is one of many different ways to accomplish this. You may want to move the method to homeController completely. Or you may wish to have IB use the rootViewControllers' methods directly...
Here is another discussion of this.
First off your code doesn't really make sense. Why are you adding your HomeViewController in a -viewDidLoad call. If you want to load the HomeViewController as the initial view, you should set that in Interface Builder instead of RootViewController. When you want to display a new view controller, you should be using a navigation controller stack and pushing the new view controller onto it with [[self navigationController] pushViewController:newViewController animated:YES].
Assuming you get that sorted, you should create a delegate (id) field for your child view controller that you can set when you instantiate the new view controller. So your code might look something like this:
HomeViewController *homeController=[[HomeViewController alloc]
initWithNibName:#"HomeView" bundle:nil];
[homeController setDelegate:self];
[[self navigationController] pushViewController:homeController animated:YES];
[homeController release];
Then, when your action gets fired in the HomeViewController, you can check to see if the delegate is set and if so, call the selector in question, like this:
- (IBAction)action:(id)sender;
{
if (delegate && [delegate respondsToSelector:#selector(loadNewGame)])
[delegate performSelector:#selector(loadNewGame)];
}
You might want to read Apple's docs on how to use the navigation controller stack. This might help clarify some things.

Unable to pushViewController for subview

I have a UINavigationController and I have seperate UIViews that I switch between using a UISegmentControl. On switching the views, I add the view as a subview to my navigation controller's view:
[self.view addSubview:segmentTab1.view];
and
[self.view addSubview:segmentTab2.view];
Then, in the subViews, each has a UITableView, but my issue is, that I am unable to push a new viewController into view in the didSelectRowAtIndexPath method.
The method is called correctly and by setting breakpoints, I can see the method for pushing the view gets called as well, but nothing happens. This is my code for pushing it:
[self.navigationController pushViewController:detailsViewController animated:YES];
I also tried
[super.navigationController pushViewController:detailsViewController animated:YES];
What am I doing wrong - or is is just not possible to do it with a subview?
When you call -pushViewController, which view controller is self? If you are calling that from within one of your tab subviews, self likely doesn't have a reference to the navigation controller from the top level view that you added it to. You can verify this by getting the memory address of the navigation controller from within the top level view and comparing it to what you have in the subview. Obviously if it's nil or doesn't match, then that's your problem.
You only get a navigation controller "for free" when it's been added to the navigation stack itself with -pushViewController which your subviews haven't been added that way.
I had a similar issue when implementing a common header for all the views
After many tries , i have fixed it by this -
In all the viewController
- (void)viewWillAppear:(BOOL)animated {
[self.view addSubview:[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] view]];
[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] viewWillAppear:YES];
}
I have referred following post to implement the header view
Common XIB in multiple View Controller in iPhone
[self.view addSubview:[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] view]]; // line will load the header subview
[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] viewWillAppear:YES]; // this is to call the viewWillAppear method of HeaderController where we can write code to check the user is logged or not and change the login button to logout button etc ..
Instead of
[self.view addSubview:segmentTab1.view];
and
[self.view addSubview:segmentTab2.view];
you may use
[self pushViewController: segmentTab1 animated: NO];
and
[self pushViewController: segmentTab2 animated: NO];
to add your viewControllers to the navigation hierarchy, and make [super.navigationController pushViewController:detailsViewController animated:YES]; work.
It is not entirely clear to me what your view hierarchy is, but in general if your navigation controllers view is not the first subview of a window or an element of one of Apple's collection views (either another navigation view controller's content view or a tab controller's content view) it won't work correctly.
One possibility, if you are not averse to singletons, is to make your product's UINavigationController object be a singleton, accessible from (for example) your application delegate.
You would invoke it thus:
[[((MyApplicationDelegate*)[UIApplication delegate]) navController]
pushViewController: viewControllerToPush animated: YES];
where within MyApplicationDelegate, navController returns the singleton object.
LogEntryDetailViewController *leController = [[LogEntryDetailViewController alloc] initWithNibName:#"LogEntryDetailView" bundle:[NSBundle mainBundle]];
[leController setTitle:[NSString stringWithFormat:#"%#", [logEntriesArray objectAtIndex:row]]];
[[self navigationController] pushViewController:leController animated:NO];
[leController release], leController = nil;

Can presentModalViewController work at startup?

I'd like to use a modal UITableView at startup to ask users for password, etc. if they are not already configured. However, the command to call the uitableview doesn't seem to work inside viewDidLoad.
startup code:
- (void)viewDidLoad {
rootViewController = [[SettingsController alloc]
initWithStyle:UITableViewStyleGrouped];
navigationController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
// place where code doesn't work
//[self presentModalViewController:navigationController animated:YES];
}
However, the same code works fine when called later by a button:
- (IBAction)settingsPressed:(id)sender{
[self presentModalViewController:navigationController animated:YES];
}
Related question: how do I sense (at the upper level) when the UITableView has used the command to quit?
[self.parentViewController dismissModalViewControllerAnimated:YES];
You can place the presentModalViewController:animated: call elsewhere in code - it should work in the viewWillAppear method of the view controller, or in the applicationDidFinishLaunching method in the app delegate (this is where I place my on-launch modal controllers).
As for knowing when the view controller disappears, you can define a method on the parent view controller and override the implementation of dismissModalViewControllerAnimated on the child controller to call the method. Something like this:
// Parent view controller, of class ParentController
- (void)modalViewControllerWasDismissed {
NSLog(#"dismissed!");
}
// Modal (child) view controller
- (void)dismissModalViewControllerAnimated:(BOOL)animated {
ParentController *parent = (ParentController *)(self.parentViewController);
[parent modalViewControllerWasDismissed];
[super dismissModalViewControllerAnimated:animated];
}
I had quite the same problem. I know the topic is old but maybe my solution could help someone else...
You just have to move your modal definition in a method:
// ModalViewController initialization
- (void) presentStartUpModal
{
ModalStartupViewController *startUpModal = [[ModalStartupViewController alloc] initWithNibName:#"StartUpModalView" bundle:nil];
startUpModal.delegate = self;
[self presentModalViewController:startUpModal animated:YES];
[startUpModal release];
}
Next, in viewDidLoad, call your modal definition method in a performSelector:withObject:afterDelay: with 0 as delay value. Like this:
- (void)viewDidLoad
{
[super viewDidLoad];
//[self presentStartUpModal]; // <== This line don't seems to work but the next one is fine.
[self performSelector:#selector(presentStartUpModal) withObject:nil afterDelay:0.0];
}
I still don't understand why the 'standard' way doesn't work.
If you are going to do it like that then you are going to have to declare your own protocol to be able to tell when the UITableView dismissed the parentViewController, so you declare a protocol that has a method like
-(void)MyTableViewDidDismiss
then in your parent class you can implement this protocol and after you dismissModalView in tableView you can call MyTableViewDidDismiss on the delegate (whihc is the parent view controller).