Shake to open view modally - iphone

I have my 'shake' working fine (using motionEnded), based off of Apple's GLPaint code. When the user shakes the device (running 3.0 and up) I want to open a view controller modally using presentModalViewController.
In my appdelegate I have the notification (as per the GLPaint sample code):
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(shakeToOpenHiddenScreen) name:#"shake" object:nil];
In my shakeToOpenHiddenScreen I just want to open view 'x' modally but I don't think that my appdelegate will respond to presentModalViewController.
Is there a way around this?

To use presentModalViewController you have to use it from a UIViewController class, or subclass:
For example:
//RootViewController.m
[self.navigationController presentModalViewController:loginRegView animated:YES];
You can way around this problem by defining a navigation controller into your app delegate:
//yourApp_comAppDelegate.h
UINavigationController *nav;
...
#property(nonatomic,retain) UINavigationController *nav;
and synthesize it
#syntetize nav;
To use presentModalViewController you have to use it from a UIViewController class, or subclass:
For example:
//RootViewController.m
[self.navigationController presentModalViewController:loginRegView animated:YES];
You can way around this problem by defining a navigation controller into your app delegate:
//yourApp_comAppDelegate.h
UINavigationController *nav;
...
#property(nonatomic,retain) UINavigationController *nav;
synthesize it
//yourApp_comAppDelegate.m
#synthesize nav;
and now you can use the method:
//yourApp_comAppDelegate.m
[nav presentModalViewController:yourView animated:YES];
but, first you have to assign it somewhere, i will do it in the RootViewController
//RootViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
app = (yourApp_comAppDelegate *) [[UIApplication sharedApplication] delegate];
app.nav = self.navigationController
}
It should work, let me know :)

It is a method on UIViewController, so you should either have access to a saved view controller from your appDelegate, or else set up the notification to call one (addObserver:someVC).
"shake" isn't a standard notification name, so there should be some code elsewhere in your app that posts this notification, presumably also copied from the GLPaint sample.

Related

Correct way to propagate shouldAutorotate into a deep modal viewcontroller in iOS6

What is the correct way to propagate shouldAutorotate into a deep modal viewcontroller in iOS6
Consider the following example:
Create a new sample Tabbed Application in XCode 4.5
In the Summary, select all orientations
Create a new simple UITabBarController, e.g. MyTabBarViewController and add the code
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
In the AppDelegate, replace with UITabBarController by MyTabBarViewController in order to hook the rotation
self.tabBarController = [[MyTabBarViewController alloc] init];
Now the rotation should work, and in the FirstViewController, add the code to show a modal viewcontroller on click
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIViewController * viewController2 = [[SecondViewController alloc]
initWithNibName:#"SecondViewController_iPhone" bundle:nil];
[self presentViewController: [[UINavigationController alloc]
initWithRootViewController:viewController2]
animated:YES
completion:nil];
}
Problem:
Now since the SecondViewController is wrapped by a UINavigationController, even I have added shouldAutorotate in SecondViewController and can't make the upside down rotation done right.
The only fix is to create a custom UINavigationController and also implement shouldAutorotate and this should work.
But this approach sound stupid and it require me to fix all UI class by implementing the shouldAutorotate and I cannot use shorthands such as [UINavigationController alloc]
initWithRootViewController... anymore, I must implement all these UITabBarController and UINavigationController.
Are there any better approach?
Have you tried this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
It's a notification sent by the device which tell the observer about the rotation. Do not forget to removeObserver when you don't need anymore
That is not stupid, and it's seems to be the right way.
You could create a subclass of UINavigationController, and use
[[MyNavigationController alloc] initWithRootViewController:...].

Common XIB in multiple View Controller in iPhone

I have an iPhone Application with multiple view controllers , in all view controller's header is common.
I dont want to use the same method and create common view in all controllers.
So My questions is how do i use this common view in all controllers.
Use initWithNibNamed:"name of your xib" when you alloc your new view controller. It's simple.
Same but we can avoid defining a variable -
[self.view addSubview:[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] view]];
ok so you have to create it in Application Delegate once.
in .h
#property(nonatomic,strong) uiviewcontroller headerview;
in .m
#synthesize headerview=_headerview;
then alloc it in "didFinishLaunchingWithOptions" in appdelegate as singleton
self.headerview = [[headerview alloc] initWithNibName:#"headerview" bundle:nil];
So every time you want to add it to your view.
Create object from application delegate in your class after import it.
applicationdelegate app = [uiapplication sharedapplication]delegate];
[self.view addsubview:app.headerview.view];

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];
}];

Change from UIViewController to UITableViewController

This one make me go crazy. I am building an iphone app where the first view is a login view. UIViewController, when the user succesfully logs in i want to display i table view. Somehow i just have big problems doing this.
In my app delegate i load my loginViewController, and then i want from the loginViewController load my listViewController.
What is the logic behind switching to a UITableViewController from a UIViewController?
you'd better to do it in your app delegate and surely NOT add the UITableViewController.view to the UIViewController.view... just add it to the UIWindow and then dismiss the old UIViewController (removeFromSuperView it's view and then release it)
EDIT:
that's how i manage:
i add a method in my appDelegate:
-(void)switchMainView;
and from my UIViewController i just call it with this:
[[[UIApplication sharedApplication] delegate] switchMainView];
in switchMainView i just
remove my UIViewController.view from superview,
release UIViewController,
alloc the UITableViewController and init it, then
add its view to the window app:
-(void)switchMainView{
if (mainView!=nil){ // mainView is the UIViewController
[mainView.view removeFromSuperview];
[mainView release];
mainView = nil;
}
Menu *vc; // Menu is my class, subClass of a UITableViewController
vc = [[Menu alloc] init];
nc = [[UINavigationController alloc] initWithRootViewController:vc];
[window addSubview:nc.view];
[vc release];
}
and then i do the same for going back, eventually
Assuming you already have your custom UITableViewController created:
YourTableViewController *vc = [[UITableViewController alloc] initWithStyle:...];
[self presentModalViewController:vc animated:YES];
[vc release];
you can use either i do'nt think there is a major impact but definitely they might have some advantage/Disadvantage over other..
for better understanding read the below tutorial.
http://cocoawithlove.com/2009/03/recreating-uitableviewcontroller-to.html

Call Function in Underlying ViewController as Modal View Controller is Dismissed

I have a mainViewController. I call [self pushModalViewController:someViewController] which makes someViewController the active view.
Now I want to call a function in mainViewController as someViewController disappears with [self dismissModalViewController].
viewDidAppear does not get called probably because the view was already there, just beneath the modal view. How does one go about calling a function in the mainViewController once the modalView dismisses itself?
Thanks a lot!
This answer was rewritten/expanded to explain the 3 most important approaches (#galambalazs)
1. Blocks
The simplest approach is using a callback block. This is good if you only have one listener (the parent view controller) interested in the dismissal. You may even pass some data with the event.
In MainViewController.m
SecondViewController* svc = [[SecondViewController alloc] init];
svc.didDismiss = ^(NSString *data) {
// this method gets called in MainVC when your SecondVC is dismissed
NSLog(#"Dismissed SecondViewController");
};
[self presentViewController:svc animated:YES completion:nil];
In SecondViewController.h
#interface MainViewController : UIViewController
#property (nonatomic, copy) void (^didDismiss)(NSString *data);
// ... other properties
#end
In SecondViewController.m
- (IBAction)close:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
if (self.didDismiss)
self.didDismiss(#"some extra data");
}
2. Delegation
Delegation is the recommended pattern by Apple:
Dismissing a Presented View Controller
If the presented view controller must return data to the presenting view controller, use the delegation design pattern to facilitate the transfer. Delegation makes it easier to reuse view controllers in different parts of your app. With delegation, the presented view controller stores a reference to a delegate object that implements methods from a formal protocol. As it gathers results, the presented view controller calls those methods on its delegate. In a typical implementation, the presenting view controller makes itself the delegate of its presented view controller.
MainViewController
In MainViewController.h
#interface MainViewController : UIViewController <SecondViewControllerDelegate>
- (void)didDismissViewController:(UIViewController*)vc;
// ... properties
#end
Somewhere in MainViewController.m (presenting)
SecondViewController* svc = [[SecondViewController alloc] init];
svc.delegate = self;
[self presentViewController:svc animated:YES completion:nil];
Somewhere else in MainViewController.m (being told about the dismissal)
- (void)didDismissViewController:(UIViewController*)vc
{
// this method gets called in MainVC when your SecondVC is dismissed
NSLog(#"Dismissed SecondViewController");
}
SecondViewController
In SecondViewController.h
#protocol SecondViewControllerDelegate <NSObject>
- (void)didDismissViewController:(UIViewController*)vc;
#end
#interface SecondViewController : UIViewController
#property (nonatomic, weak) id<SecondViewControllerDelegate> delegate;
// ... other properties
#end
Somewhere in SecondViewController.m
[self.delegate myActionFromViewController:self];
[self dismissViewControllerAnimated:YES completion:nil];
(note: the protocol with didDismissViewController: method could be reused throughout your app)
3. Notifications
Another solution is sending an NSNotification. This is a valid approach as well, it might be easier than delegation in case you only want to notify about the dismissal without passing much data. But it's main use case is when you want multiple listeners for the dismissal event (other than just the parent view controller).
But make sure to always remove yourself from NSNotificationCentre after you are done! Otherwise you risk of crashing by being called for notifications even after you are deallocated. [editor's note]
In MainViewController.m
- (IBAction)showSecondViewController:(id)sender
{
SecondViewController *secondVC = [[SecondViewController alloc] init];
[self presentViewController:secondVC animated:YES completion:nil];
// Set self to listen for the message "SecondViewControllerDismissed"
// and run a method when this message is detected
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(didDismissSecondViewController)
name:#"SecondViewControllerDismissed"
object:nil];
}
- (void)dealloc
{
// simply unsubscribe from *all* notifications upon being deallocated
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didDismissSecondViewController
{
// this method gets called in MainVC when your SecondVC is dismissed
NSLog(#"Dismissed SecondViewController");
}
In SecondViewController.m
- (IBAction)close:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
// This sends a message through the NSNotificationCenter
// to any listeners for "SecondViewControllerDismissed"
[[NSNotificationCenter defaultCenter]
postNotificationName:#"SecondViewControllerDismissed"
object:nil userInfo:nil];
}
Hope this helps!
Using exit (unwind) segue
When you're using storyboards and segues you can use a very handy approach with minimal code to dismiss a modal view controller and inform the underlying view controller that the modal view controller has been closed.
Using exit (unwind) segues you gain 3 advantages:
you don't need to write any code to dismiss the modal view controller and
you can have iOS call a callback method inside the underlying view controller that has presented the model view controller.
you use the very same semantics that you already know from implementing prepareForSegue:
Implement it with only 2 steps
Create an action method in the Parent view controller that presents another (modal) view controller:
Swift
#IBAction func unwindFromSegue(segue: UIStoryboardSegue) {
print("Unwind from segue", segue.identifier)
}
Objective-C
- (IBAction)unwindFromSegue:(UIStoryboardSegue *)segue {
NSLog(#"Unwind from segue %s", segue.identifier);
}
In the storyboard, On child view controller right click the exit segue (aka unwind segue, it's the last of the icons at the top of your view controller), drag & drop unwindFromSegue: to your button and select action.
You're done! Now the modal view controller closes when you click the dismiss button and unwindFromSegue: informs your underlying view controller(Parent) that the modal view controller(Child) has closed.
Here's a callback solution which takes less modifications to your modal and parent:
In the Model's .h add:
#property (nonatomic, copy) void (^dismissed)();
In the Model's .m put this in the completion when you dismiss the modal:
[self dismissViewControllerAnimated:YES completion:^{
if(self.dismissed)
self.dismissed();
}];
In the parent view controller when you instantiate your modal set the dismissed callback:
Modal = //Init your modal
[Modal setDismissed:^{
//do stuff you wanted when it's dimissed
}];
[self presentViewController:Modal animated:YES completion:nil];