Gestures handled identically in iPhone and iPad - iphone

I'm working on an app right now where a tap will be handled identically on the iPhone as on the iPad. I don't have an iPhone, so I'm using the simulator to test for now. I thought I could simply click with my mouse on the screen if the simulator to simulate taps, but that doesn't seem to work.
So I had the thought that maybe the problem was that I started with iPad and created the iPhone interface later (although the project itself was generic from the start).
I copied the gesture recognizers (tap and two swipes) from the storyboard for the iPad and pasted them into the storyboard for the iPhone. I didn't think this was going to work, but I was hopeful that's all I would have to do. In any case, it seems like the same code should be able to be linked from both storyborad gesture recognizers.
When that didn't work, I hooked up the iPhone gesture recognizers using Control-drag just like I did with the iPad. This created new methods. Since the same code could be used, I thought I'd simply call the other:
- (IBAction)tapIphone:(UITapGestureRecognizer *)sender {
[self tapIpad:sender];
}
- (IBAction)tapIpad:(UITapGestureRecognizer *)sender {
omitted code
}
That didn't work either. So next I tried copy/pasting the code from the iPad method to the iPhone method. It still didn't work.
So now I'm wondering if maybe I don't know how to test taps properly on the iPhone simulator. What else could I have missed?

It seems clear that the tapIphone method is not being called at all. You can work that out by adding #NSLog("tapIphone") in the method, see if it logs. In fact put these lines into their respective methods:
#NSLog("tapIphone");
#NSLog("tapIpad");
If tapIphone WAS getting called and the tapIpad method IS in the same class, the expected behaviour should have occurred.
Your first intuition, to copy and paste items from one storyboard to the other, is fine. However you lose all IBAction / IBOutlet connections when you do this (they don't carry over their links to and from the old storyboard, they just go), so you have to rewire them each time. Which is a bit of a pain when you are trying to adapt interface from one device for another. This does not mean that you have to create new code - it just means you have to CRTL-drag from each storyboard item onto the existing IBAction code item you want to reconnect to (you can achieve the same result by CTRL-dragging from the storyboard item to the relevant controlView storyboard icon, which will present you with a list of optional IBAction items to connect to). Same goes for any IBOutlet connections you want to replicate.
This is not an issue with the simulator, you just need to tweak your understanding of storyboard wiring.
I would not recommend your suggestion of separate IBAction methods as a way to handle different behaviours on different devices. This will lead to more wiring complexity which is irritating to debug. There are better ways to do that, for example by checking environment capabilities or using:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
//iPhone code goes here
} else {
//ipad code goes here
}

Related

setStatusBarOrientation causing problems in iOS8

I'm having real problems with my apps under iOS8. I've made a bunch of OpenGL based apps, which don't need the iOS to handle the orientation. It's all handled within the OpenGL section. But I do use setStatusBarOrientation to make sure any dialogs/keyboards etc that pop up line up with everything else. I'm creating my window and view programatically or in a xib, I've never needed to use a storyboard (in case thats relevant?)
It's all been perfect, til iOS 8 came along.
Now it seems that setStatusBarOrientation isn't behaving properly at all. It's either not changing anything, or it's rotating "something" that stops touches being recorded on half the screen. It's as if the window is being rotated within itself, but visually nothing changes, just the touches are effected.
It's hard to explain, and makes no sense.
But my question is: How do you set the status bar orientation in iOS8? And how do you do it without destroying everything else that works in previous iOS versions?
Set iOS7.1 as your Base SDK, and it'll work fine on iOS8, without all these strange bugs.
http://objcsharp.wordpress.com/2014/09/21/how-to-get-back-the-ios-7-sdk-after-upgrading-to-xcode-6/
found this
if ([UIViewController class]) // iOS8 has this class only
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:#"orientation"];
}
found here:
http://blog.lessfun.com/blog/2014/09/24/ios8-issue-keyboard-orientation-and-idletimerdisabled-not-working/
seems to work

Return to mainview from webView deployed using storyboard

I created a new project "Single View Application" and designed the mainView with Storyboard. My main view contains a UIButton that opens the camera, the camera scans barcode and automatically goes to a website. Now I created a webView programmatically so that website can open and also created a UIButton inside the webView. Now I want that UIButton to act as home botton and return to mainview. I am unable to do that, please help.
ViewController.m code: http://cl.ly/FKj8
My storyboard looks like:
You really should look into the View Controller Programming Guide -- by switching around the contents of a single view controller, you're making a lot of extra work for yourself with little benefit. By using multiple view controllers when you want to have different "screens" in your app, you can take advantage of storyboarding for easier development, and you automatically get better memory management (read: less potential for crashes), too.
However, to more directly answer your question... if you're putting the WebView into the view hierarchy with [self.view addSubview:webView], you can remove it with [webView removeFromSuperview]. (This means you'll have to keep a reference to the WebView around so you can refer to it when you want to dismiss it.)
I also noticed in the code you posted to cl.ly an unrelated method -deviceModel which uses uname() to get device information. This is a bad idea, for two reasons:
uname() isn't guaranteed to do something useful on an iOS device (even if it currently does). Use the UIDevice class instead if you need this kind of info, or...
Generally, you don't want to test for the device name to enable functionality in your app; instead, you should test for the capabilities you need. (For example, if you look for a device name starting with "iPhone 4" to test for a Retina display, you'll miss the 4th-generation iPod touch, and the iPhone-5-or-whatever-they-call-what's-next. Instead, use the UIScreen class.)

shouldAutorotateToInterfaceOrientation doesn't work on first launch after fresh app install

When the app I'm working on is installed either via Ad-Hoc thru iTunes or built directly to the device, upon launching for the first time, the only view controller in my app that responds to orientation changes doesn't receive calls to shouldAutorotateToInterfaceOrientation: with a landscape argument passed in; debugging shows that it's only being called for portrait. Every subsequent launch behaves as I would expect - that is, there are calls to shouldAutorotateToInterfaceOrientation: made both with landscape and portrait arguments. This exact behavior can be seen in the iPhone simulator, on the iPhone and on the iPod touch.
So my question is: why would orientation notifications be different for the first launch of an app than they would be for every subsequent launch? Am I mistaken in believing that I have no control over orientation changes beyond responding to shouldAutorotateToInterfaceOrientation:?
Inside the ViewController in question:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
and inside of viewDidLoad and viewDidUnload I've got (respectively):
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
and
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
Update July 6, 2010:
Still no luck solving the problem. I dropped the issue for a little while and came back to it and am still seeing the problem under completely different circumstances. Anyone?
Update July 13, 2010:
From Apple's View Controller Programming Guide:
"...the window object does much of the work associated with changing the current orientation. [...] Specifically, it works with the view controller whose root view was most recently added to, or presented in, the window. In other words, the window object works only with the frontmost view controller whose view was displayed..."
I'm adding the root view controller to the window differently on the first launch compared to every subsequent launch, so I thought maybe it had something to do with this. I have yet to trace anything back to here though...just a thought.
This thing has had around 175 views at the time of this update...no one has even the most far out obscure suggestion? Come on, throw something out there. I'm willing to entertain any guesses or suggestions at this point. I don't care if it's stupidly obscure or potentially irrelevant.
Never did solve this problem - I left the company where I encountered it before I had a chance to. However, I had a pretty good lead on it by the time I left. I contacted Apple DTS about the issue and they noted that for autorotation to work properly, all ViewControllers in the view stack related to autorotation must call the super methods in the method implementations (i.e. calling [super viewDidLoad] from within the ViewController's viewDidLoad). I don't remember which methods they cited exactly, but it's probably worth a shot to ensure you're properly calling super where appropriate.
[EDIT] If someone can confirm this, I'll mark it as the accepted answer. Thanks!
also make sure you set:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;}
in ALL ViewControllers.m in your app, not just one you're working on (if you have more than one). I was struggling trying to get it going for the FirstViewController, but it wouldn't work no matter what. As soon as I added the above code to all four view controllers, it started to work just fine (in all four)
I had a similar problem - the UIDevice.h header lists endGeneratingDeviceOrientationNotifications and beginGeneratingDeviceOrientationNotifications as "nestable." It turns out I had unbalanced calls to these methods.
I solved this quickly with the following change to beginGeneratingDeviceOrientationNotifications:
if (![[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications])
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

shouldAutorotateToInterfaceOrientation & UINavigationController

I'm trying to implement auto-rotation in my application that is basically UINavigationController with lots of UIViewControllers that get pushed onto it.
I've copy-pasted this in my first UIViewController (that gets pushed into UINavigationController):
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Everything worked fine... However, if I paste in that code into second UIViewController (that first one pushes on top after some button click) - autorotation won't work. shouldAutorotateToInterfaceOrientation gets called when UIViewController is first initialized, but after it is visible and I rotate device - nothing happens.
So result is: first view gets rotated well - portrait/landscape... but after I click button and get into second view I remain stuck into that portrait or landscape, whatever was active.
I tried subclassing UINavigationController and setting shouldAutorotateToInterfaceOrientation there, but that also doesn't work.
What am I doing wrong?
There's a bug in the API that doesn't cause it to work for the second view. I solved it originally using setOrientation, but that's a private API and thus not a reasonable solution. I haven't released any new versions of the application while I try to figure out alternatives (and I don't think having customers upgrade to OS 4.0 is a solution). I'm thinking I'll need to manually keep track of the orientation and rotate my views manually to counteract the effects of the wrong rotation.
You need to implement this method in all views in the hierarchy

Single-Stage vs Two-Stage Animation for iPhone Apps?

What are single-state and two-stage animation for rotating an iPhone window?
This is the "error" message I get in the Debugger Console (nothing crashes):
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
I was working through the book "Beginning iPhone Development: Exploring the iPhone SDK" by Apress (Dave Mark, Jeff LaMarche) on the Swap Project.
Everything is explained in the UIViewController Class Reference. Especially check out the View Rotation section near the top.
From the reference:
Handling View Rotations
By default, the UIViewController class
displays views in portrait mode only.
To support additional orientations,
you must override the
shouldAutorotateToInterfaceOrientation:
method and return YES for any
orientations your subclass supports.
If the autoresizing properties of your
views are configured correctly, that
may be all you have to do. However,
the UIViewController class provides
additional hooks for you to implement
additional behaviors as needed.
To temporarily turn off features that
are not needed or might otherwise
cause problems during the orientation
change, you can override the
willRotateToInterfaceOrientation:duration:
method and perform the needed actions
there. You can then override the
didRotateFromInterfaceOrientation:
method and use it to reenable those
features once the orientation change
is complete.
If you want to perform custom
animations during an orientation
change, you can do so in one of two
ways. Orientation changes used to
occur in two steps, with notifications
occurring at the beginning, middle,
and end points of the rotation.
However, in iPhone OS 3.0, support was
added for performing orientation
changes in one step. Using a one-step
orientation change tends to be faster
than the older two-step process and is
generally recommended for any new
code.
To add animations for a one-step
orientation change, override the
willAnimateRotationToInterfaceOrientation:duration:
method and perform your animations
there. To use the older two-step
method, override one or both of the
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
and
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
methods to configure your animations
before each step. You must choose only
one technique and override just the
methods associated with that
technique. If you override either
method associated with the two-step
technique, the view controller uses
that technique by default.
I have found the culprit in my case to be the UIImagePickerController (I also do not override any rotation animation):
[self presentModalViewController:imagePicker animated:YES];
Replacing imagePicker with a generic UIViewController doesn't generate any warnings.
I changed from willAnimateFirstHalfOfRotationToInterfaceOrientation:duration: method to willAnimateRotationToInterfaceOrientation:duration: method and warning gone.
Thanks.
Ed Marty's answer is the correct one. The reason it will happen if you are not overriding any of the rotation animation is probably that you reply "YES" to shouldAutorotate.. for some view. If you do not implement rotation at all, then you should just not override the shouldAutorotate.. method. If you do override that method, then just override the single step rotation method as well and pass it along to the super.
If you're using iOS 4 and you're getting this warning, I found a way to get rid of it. In your info.plist, there is an item called "Supported interface orientations." Select which orientations your application supports and two-stage warnings will go away when bringing up the imagePicker.
#plumiscles answer didn't quite work for me - there was no item called 'Supported Interface Orientations', probably b/c it is an old project. But you can get the same effect by editing the .plist file directly and adding this:
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationPortrait</string>
Need to add UIImagePickerController as a subview to solve this error
[self.view addSubview:picker.view];
[self presentModalViewController:picker animated:NO];
I've had this issue after creating a tabbarcontroller with no view controllers inside (no tabs), this warning disappeared once I attached at least one view controller to it.
I wasn't over riding any of those two-step functions, but I was calling my own function when I received orientationChanged notifications, and I had this line of code in it. Commenting it out got rid of the warning and allowed the auto rotate to work properly. Auto rotate still worked with this line of code until iOS 4.2, then it broke completely. Spent a lot of time looking for why the built in autoRotate stopped working in 4.2. Maybe this will help someone else.
Commented out this line to make it work:
[[UIApplication sharedApplication] setStatusBarOrientation:currentOrientation animated:YES];
I've delete from plist "Supported interface orientations" row and warning disappears.
I just had the same problem. In my case was a silly mistake that I'm putting here just in case anyone else falls into that same issue.
In my tabbed app I remove one of the original ViewControllers and added a new one with Storyboard to create a "Settings" section.
This new VC had to be a table view VC and even I designed, compiled and run it without a problem, when I changed the orientation of the app I kept getting this “Using two-stage rotation animation” error.
My problem was that I forgot to change in the original .h file interface "UIViewController" for "UITableViewController".
Once this was done I changed on the Storyboard identity badge the class from the general value to my SettingsViewController and that was the end of it.
I hope it can help someone else. It took me a while to get to bottom of this.
Cheers,