Xcode app is stuck in landscape mode - objective-c

I've just recently begun learning to use Xcode and Objective-C. As usual, I decided to begin by learning how to create a Hello, World app.
For some reason, even though I'm designing everything for portrait mode, it keeps showing landscape mode in the simulator and on my iPad 2.
In Xcode
In the simulator an on the iPad
Here is the code of the view controller, if that helps at all.
#import "LCViewController.h"
#interface LCViewController ()
#end
#implementation LCViewController
#synthesize helloButton;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setHelloButton:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)showAlert:(id)sender {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle: #"Hello!"
message:#"Hello, world!"
delegate:nil
cancelButtonTitle:#"Close"
otherButtonTitles:nil];
[alert show];
[helloButton setTitle:#"I was clicked!" forState:UIControlStateNormal];
}
#end
EDIT: With Red background

Supported orientations was accidentally set to landscape.
Set orientation on the project main screen in the Supported Orientations section or in the plist file.

See in the attributes inspector what voice is selected for "mode".

Related

MPMediaPickerController - iOS7

I developed test application on iOS 7 that pick the music from music library using MPMediaPickerController.
But when I present the media picker controller,it shows empty screen.
This is the code
(void) pickSong
{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO;
mediaPicker.prompt = NSLocalizedString(#"Select Your Favourite Song!", nil);
[mediaPicker loadView];
[self.navigationController presentViewController:mediaPicker animated:YES completion:nil];
}
#pragma mark - MPMediaPickerController delegate
(void) mediaPicker:(MPMediaPickerController *) mediaPicker2 didPickMediaItems:(MPMediaItemCollection *) mediaItemCollection {
[self dismissViewControllerAnimated:YES completion:nil];
MPMediaItem *mediaItem = [[mediaItemCollection items] objectAtIndex:0];
self.item.soundName = [mediaItem valueForProperty:MPMediaItemPropertyTitle];
self.item.soundUrl = [[mediaItem valueForProperty:MPMediaItemPropertyAssetURL] absoluteString];
}
(void) mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker{
[self dismissViewControllerAnimated:YES completion:NULL];
}
Please help me out.
This is an iOS bug, but it only occurs when running a 32 bit build on a 64 bit (A7) device (Only iPhone 5S for now). To work around it, add a 64 bit architecture to your app. (Open build settings in xcode, and change Architecture from $ARCHS_STANDARD to $ARCHS_STANDARD_INCLUDING_64_BIT.) You will then probably need to fix a number of compile, link and runtime issues. See Apple's 64-Bit Transition Guide.
Seems like there is a bug in ios7 where it doesn't like to be presented inside a uinavigation controller - try presenting it directly from a view controller.
I had the same problem and for me the solution was a combination of two of the solutions presented here. First I had to convert my app to be 64-bit ready by changing Architectures to "standard... (including 64-bit)". Once I corrected all the warnings that caused, I had to change the MPMediaPickerController to be presented modally rather than on the navigation stack:
- (IBAction)didSelectMusicPicker:(id)sender {
MPMediaPickerController *picker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
picker.delegate = self;
picker.allowsPickingMultipleItems = YES;
picker.prompt = NSLocalizedString (#"Add songs to play", "Prompt in media item picker");
//[self.navigationController pushViewController:picker animated:YES];
[self presentViewController:picker animated:TRUE completion:NULL];
}
Of course, I also needed to change mediaPicker:didPickMediaItems: and mediaPickerDidCancel: to use dismissViewControllerAnimated. Once all that was fixed, the picker worked as expected on both iPhone 4 and iPhone 5S running iOS 7.
a thought: is the presented screen completely empty, or are you getting the navigation bar at the bottom but with no tracks listed? I've noticed that as of iOS 7 the picker now defaults to opening to the Playlist tab (it used to open to Albums, if I recall)… if you have no playlists on the device that would account for the empty screen…
I can see the list of songs and select the songs. But I cannot dismiss the view controller on pressing "Done". I've tried PresentViewController since Modal controller is deprecated.
- (IBAction) showMediaPicker: (id) sender {
picker =
[[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeAnyAudio];
picker.delegate = self;
picker.allowsPickingMultipleItems = YES;
picker.prompt = NSLocalizedString (#"AddSongsPrompt", #"Prompt to user to choose some songs to play");
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleDefault animated:YES];
[self.picker removeFromParentViewController];
[self presentViewController:picker animated:YES completion:nil];
// [picker release];
}
// Responds to the user tapping Done after choosing music.
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
[self.picker removeFromParentViewController];
[self dismissViewControllerAnimated:YES completion:nil];
//
[self.delegate updatePlayerQueueWithMediaCollection: mediaItemCollection];
// [self.mediaItemCollectionTable reloadData];
// [[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque animated:YES];
}
I've tried RemovefromSuperview also, nothing seems to work. I'm testing this on an iPhone 6 simulator and an iPhone 5 with iOS 8.1.3.
Anyone???
I also have the same problem before. But I found out just need to restart the device after upgrade. The music picker appear again.

iOS6 landscape app with only one controller multioriented popViewController issue

I have this setup to support only landscape orientation in most of my viewcontrollers
My app delegate has this piece of code:
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
NSUInteger orientations = UIInterfaceOrientationMaskLandscape;
if (self.window.rootViewController) {
UIViewController * pressented = [[((UINavigationController *)self.window.rootViewController) viewControllers] lastObject];
orientations =[pressented supportedInterfaceOrientations];
}
return orientations;
}
And in most viewcontrollers this:
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
My problem comes when I push THIS controller (the one I would like to rotate):
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskALL;
}
It rotates perfectly BUT when I pop the viewcontroller (tap the back button of the navigation bar) with the orientation in portrait, the presenting viewcontroller also sets it's orientation to Portrait.
How can I make the presenting viewcontroller stays locked on landscape, or force the problematic controller to rotate back to landscape before popping.
Add this to your portrait view controller:
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
UIViewController* dummyController = [[UIViewController alloc] init];
[self presentViewController:dummyController animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
}
I know it's a hack, but it works. Anyone knows a better solution?

iOS 6 Orientation rotate automatically back to portrait on pressing done on MoviePlayer

I am using MoviePlayer controller to play a video in my iOS app. I am using orientation notification like this
if(deviceOrientation ==UIDeviceOrientationLandscapeLeft)
{
NSLog(#"Replay is in Landscape");
self.fullScreenFlag = YES;
[self.moviePlayer setFullscreen:YES animated:NO];
}
This makes my video screen to play in full screen when user turns the phone to landscape orientation. But when I press done button on moviePlayer control I go into following method
- (void)movieWillExitFullscreen:(NSNotification*)notification
{
UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
if(deviceOrientation ==UIDeviceOrientationLandscapeLeft) {
NSLog(#"Pressed Done in Landscape");
//Problem: Here I want to force my VideoViewController to rotate back to portrait Mode
}
}
Not sure how can I make the VC to go back to portrait as soon as user pressed done button or video stops playing. I am aware to the moviePlayerNotificationMethods but what should I call in those method for orientation is not clear.
I solved this issue by having a separate view controller for the video playback.
So, you would have two view controllers
SomeViewController
MoviePlayerViewController
In your SomeViewController, when you want to play the movie:
MoviePlayerViewController *vc = [[MoviePlayerViewController alloc] initWithNibName:#"MoviePlayerViewController" bundle:nil];
[vc setPathToMovie:path];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
And then in your MoviePlayerViewController
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
[[self navigationController] popViewControllerAnimated:YES];
}
You can then lock down your SomeViewController to portrait, and if the user is in landscape when watching the video, they will return to portrait when popping back to SomeViewController.
I never found a solution using the deviceOrientation method and a modal MPMoviePlayerController. There may be one though!
I solved this by doing this in "moviePlayBackDidFinish"
UIViewController* forcePortrait = [[UIViewController alloc] init];
[self presentViewController:forcePortrait animated:NO completion:^{
[forcePortrait dismissViewControllerAnimated:NO completion:nil];
}];
It's not beautiful but it works like a charm :-)
Depending upon whether you using MPMoviePlayerController within a ViewController or as a separate ViewController the answer is as follows :-
Firstly :- This link will explain you how to restrict some views to portrait and allow others to rotate?
In that link you will see that, in the NavigationViewController you have made, following changes:-
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
What it does is, it give the child to make their own decision if they want to auto-rotate or not.
Next the ViewController containing your MoviePlayer should do this :-
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Once you have done this, it gives the power of AutoRotation to your ViewController.
Now here's the tricky part, see I assume that you might have restricted your ViewController to Portrait, and since movie player allows you go fullscreen and in fullscreen when you rotate your screen it will turn to landscape, and now if you press done button it won't turn to portrait rather it will exit the fullscreen in landscape itself. In this case what you should do is, in your:-
- (BOOL)shouldAutorotate
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft) {
if ([[[self.navigationViewController.viewControllers] lastObject] class] == [MoviePlayerViewController class] ) {
return YES;
}
return NO;
}
return NO;
}
So, what it does is, you should auto-rotate only when the orientation is landscape and not when its portrait.
So far so good, next comes the MoviePlayer, considering that you have already played the Video and your only interest is when we click "Done" button it should auto-rotate to portrait.
Register for a notification to your MoviePlayer
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerWillExitFullScreen:) name:MPMoviePlayerWillExitFullscreenNotification object:_moviePlayer];
Then in the selector:
- (void) moviePlayerWillExitFullScreen:(NSNotification*)notification{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerWillExitFullscreenNotification object:_moviePlayer];
}
Tada! the magic is done! try out let me know ;-)

Xcode Page Based Application Interface Rotation Issue

Start a new page based application project in Xcode
Run the project and turn some pages
Rotate the simulator or device
=> The page view conroller switches back to the first page (january)
How can I prevent step 4. ?
EDIT:
This happens only the first time you rotate after the app started in simulator/device.
I use most recent Xcode 4.5 with iOS 6.0 Simulator and iOS 6 on my testing device.
The same thing happens when I download some other sample code from blogs / etc. Maybe an iOS 6 bug?
EDIT2:
I found out that the first page view that is passed to the UIPageViewController is not dealloced until first rotation. This really looks like a bug to me.
(UPDATE FROM 2014: This seems to have been fixed in iOS7, if you start again from a new Page View application template.)
I've experienced this bug as well. It seems to kick in any time after the main view reappears. My app has several full-screen modals in it, and after those go away the same behaviour occurs.
This happens in XCode 4.5.1 and iOS6 - I 'fixed' this by re-downloading XCode 4.4 and reverting my app back to iOS5.1. Obviously not a great long-term solution. I filed this in Radar and got a note back that it was already logged.
FWIW I noticed that iBooks had this same bug in it right after iOS6 came out, but they seem to have fixed it in a recent update.
Here's how I managed to fix this problem in my app. I'm afraid it's kind of a hacky solution, but it's a quirky bug.
Context: My app is a diary (it's called Remembary) and each page is a different day's diary entry. I have a singleton class called "AppContext" that keeps track of various app-level values, such as the currently showing diary entry object, the current date, and the like. Each day's dataViewController also keeps track of its own diary entry.
The trickiest part was finding a context where I could catch that the app was showing the wrong page. It turns out that this is in [RootViewController viewDidLayoutSubviews], so I added the following to that method:
// get the currently displaying page
DataViewController *currentPage = self.pageViewController.viewControllers[0];
// check if we're showing the wrong page
if ([currentPage myEntry] != [AppContext getCurrentEntry]) {
// jump to the proper page (the delay is needed to ensure that the rotation has fully completed)
[self performSelector:#selector(forceJumpToDate:)
withObject:[AppContext getCurrentEntryDate]
afterDelay:0.5];
}
Here's the forceJumpToDate function, which basically gets a new page based on the current date and tells the pageViewController to jump to it without animating:
- (void) forceJumpToDate:(NSDate *)targetDate {
DataViewController *targetPage = [self.modelController viewControllerForDate:targetDate
storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:targetPage];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
The user might notice a brief hiccup on the screen as the new page is forced into place, but this only happens if they would otherwise be getting the wrong page, so it's still an improvement.
This was seriously interfering with my ability to upgrade my app to iOS6, so I'm glad I finally figured it out.
Here is my solution:
// RootViewController.m
#import "RootViewController.h"
#import "ModelController.h"
#import "DataViewController.h"
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
//added
#property (strong, nonatomic) DataViewController *currentViewController;
#end
#implementation RootViewController
#synthesize modelController = _modelController;
//added
#synthesize currentViewController = _currentViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
}
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
//added
self.currentViewController = self.pageViewController.viewControllers[0];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (ModelController *)modelController
{
// Return the model controller object, creating it if necessary.
// In more complex implementations, the model controller may be passed to the view controller.
if (!_modelController) {
_modelController = [[ModelController alloc] init];
}
return _modelController;
}
#pragma mark - UIPageViewController delegate methods
/*
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
}
*/
//added
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
self.currentViewController = self.pageViewController.viewControllers[0];
}
- (DataViewController *)currentViewController
{
if (!_currentViewController) _currentViewController = [[DataViewController alloc] init];
return _currentViewController;
}
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if (UIInterfaceOrientationIsPortrait(orientation) || ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)) {
// In portrait orientation or on iPhone: Set the spine position to "min" and the page view controller's view controllers array to contain just one view controller. Setting the spine position to 'UIPageViewControllerSpineLocationMid' in landscape orientation sets the doubleSided property to YES, so set it to NO here.
//deleted: UIViewController *currentViewController = self.pageViewController.viewControllers[0];
//changed to self.currentViewController
NSArray *viewControllers = #[self.currentViewController];
[self.pageViewController setViewControllers:viewControllers
direction:UIPageViewControllerNavigationDirectionForward
animated:YES
completion:NULL];
self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMin;
}
// In landscape orientation: Set set the spine location to "mid" and the page view controller's view controllers array to contain two view controllers. If the current page is even, set it to contain the current and next view controllers; if it is odd, set the array to contain the previous and current view controllers.
// deleted: DataViewController *currentViewController = self.pageViewController.viewControllers[0];
//deleted: NSArray *viewControllers = nil;
//added
NSArray *viewControllers = #[self.currentViewController];
//changed currentViewController to self.currentViewController
NSUInteger indexOfCurrentViewController = [self.modelController indexOfViewController:self.currentViewController];
if (indexOfCurrentViewController == 0 || indexOfCurrentViewController % 2 == 0) {
UIViewController *nextViewController = [self.modelController pageViewController:self.pageViewController viewControllerAfterViewController:self.currentViewController];
viewControllers = #[self.currentViewController, nextViewController];
} else {
UIViewController *previousViewController = [self.modelController pageViewController:self.pageViewController viewControllerBeforeViewController:self.currentViewController];
viewControllers = #[previousViewController, self.currentViewController];
}
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];
return UIPageViewControllerSpineLocationMid;
}
#end
What is it you want to prevent? Do you want to prevent rotation? If that is what you want, modify the shouldAutorotateToInterfaceOrientation return value in the RootViewController.m implementation file.
When I did this, the App was able to keep the same page (month) even after rotating the device. I used the simulator and tried on both iPhone and iPad. On the iPad, in landscape mode, it showed two months at a time, but then when rotated back to portrait, still kept the first of the two months that was displayed. This was when I incremented to June. I used the default project without changing a line of code.
Today I found out that in my app I could just use the following to remove the bug (but I have no clue why).
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
...
self.pageViewController.view.hidden = YES;
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.pageViewController.view.hidden = NO;
}

initializing rootViewController from different xibs depending on the device the App runs on

Hey guys,
I Have the following Problem:
I have an IPad App and now I want it to run on IPhone also. (I know it should be the other way round, but I cant change it).
So now i want to decide which view i need by using:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// The device is an iPad running iOS 3.2 or later.
}
else {
// The device is an iPhone or iPod touch.
}
This works well for all views exept the RootViewController.
No Matter where i set the xib for the RootViewController, it always displays the one i defined for the IPad-App.
This is my Code in the App-Delegate:
viewController = [VoycerUniversalAppViewController sharedInstance];
UINavigationController *myNavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.window addSubview:myNavigationController.view];
//[self.window addSubview:self.vcSplashScreen.view];
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
And this is the Code in my [VoycerUniversalAppViewController sharedInstance]:
+ (VoycerUniversalAppViewController*) sharedInstance
{
#synchronized(self)
{
if(sharedInstance == nil)
{
// only allocate here - assignment is done in the alloc method
if (![AppState sharedInstance].loggedIn)
{
[AppState sharedInstance ].loggedIn = FALSE;
}
}
}
return sharedInstance;
}
+ (id) allocWithZone:(NSZone*)zone {
#synchronized(self) {
if(sharedInstance == nil) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// The device is an iPad running iOS 3.2 or later.
NSLog(#"The device is an iPad running iOS 3.2 or later.");
sharedInstance = [[super allocWithZone:zone] initWithNibName:#"VoycerUniversalAppViewController" bundle:nil];
}
else {
// The device is an iPhone or iPod touch.
NSLog(#"The device is an iPhone or iPod touch.");
sharedInstance = [[super allocWithZone:zone] initWithNibName:#"VoycerUniversalAppIPhoneViewController" bundle:nil];
}
// allocate and assign instance variable on first allocation
return sharedInstance;
}
}
return nil;
}
I looked almost everywhere i think if i missed some setting or something, but i couldnt find any.
Does anyone of you have an idea, why constantly loads the VoycerUnversalAppViewController instead of the other one?
Both Xibs are linked to the same class.
If the solution is a quite simple one and obvious please don't blame me, i'm really new to xcode, IB and objective-c (i code in objective-c for 1 1/2 month now).
Thx in advance.
Maverick1st.
For the main NIB, there are settings in the info.plist file: NSMainNibFile and NSMainNibFile~ipad.
In the NIB file you can create the application delegate and set up a navigation controller.