We've been having trouble with this issue for a while, and just cannot find the answer to it in the docs or online searches..
Our iOS game is based on OpenGL ES, and we are implementing GameCenter turn based gaming. The following code shows a matchmaking UI for creating a turn based match. This code works fine on my iPad 1 and iPad 3. However, it will not work on my iPhone 4S!
[ UPDATE: ] We were using a UIWindow at the top of the View hierarchy, with a GL View / Layer as a sub view. This obscured the new view when it was presented. I can see this window now by adding a UIView into the main window, and the GL view as a child of it. However, I still cannot interact with this view..
This code is from a .mm file where we mix C++ and Objective-C code.
// Configure the match making view, with our own delegate
GKTurnBasedMatchmakerViewController *mmvc =
[[GKTurnBasedMatchmakerViewController alloc]
initWithMatchRequest:request];
mmvc.showExistingMatches = YES;
// Uses our own delegate.
if(!g_pTurnBasedDelegate)
{
g_pTurnBasedDelegate = [[TurnBasedDelegate alloc] init];
}
mmvc.turnBasedMatchmakerDelegate = g_pTurnBasedDelegate;
// Get the main window's root controller and instruct it to show the match making delegate.
if(g_Env && g_Env->m_pWindow)
{
RefPtr<WindowIOS> pIOSWin = ref_static_cast<WindowIOS>(g_Env->m_pWindow);
UIWindow * pUIWin = (UIWindow *)pIOSWin->GetHandle();
UIViewController * pController = [pUIWin rootViewController];
if(pController)
{
g_pRootViewController = pController;
}
}
if(g_pRootViewController)
{
[g_pRootViewController presentViewController:mmvc animated:YES completion:nil];
}
Came back to this issue after a while. The problem was not with the Game Center controllers, but rather with how we were setting up our main application views. This just happened to work on iPad, but not on iPhone.
For our application, we need to initialize the whole view hierarchy in code instead of using a NIB / Storyboard.
Our old initialization steps were:
UIWindow init and make key.
UIWindow addView (our OpenGL window).
UIWindow addView (a touch responder UIView).
UIWindow rootViewController = [[ViewController alloc] init];
Adding our views directly to UIWindow would impede the functionality of View Controllers and cause undefined behavior on iPhone vs. iPad.
Our new initialization steps (to fix these issues if anyone is having them):
UIWindow init and make key.
UIWindow rootViewController = [[ViewController alloc] init];
rootViewController.view = [[GLAndTouchView alloc] init];
Hopefully, anyone stuck with the same problem will find this useful.
Related
I am making a game using spritekit and everything works perfectly except when I add the code to add an iAd. When I add the iAd everything works but it seems that the iAd is resizing the scene when it is being displayed.
This is my code to display the iAd, it is in the ViewController.m :
#import <iAd/iAd.h>
#import "ViewController.h"
#import "MainMenu.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.originalContentView;
skView.showsFPS = YES;
// Create and configure the scene.
SKScene * scene = [MainMenu sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
self.canDisplayBannerAds = YES;
// Present the scene.
[skView presentScene:scene];
}
Like I say, the iAd shows up, and all the function properly but the when the iAd is displayed it makes the scene smaller, is there a method or something that allows the scenes to not be resized?
An help is much appreciated, thanks!
Ok so I sort of figured it out, I was using scaleMode of SKSceneScaleModeAspectFit I have now changed it to SKSceneScaleModeFill this seems to make the scene shorter but it is not as noticeable as the aspectFit scale mode. I have also noticed that the iAd does not act like a sprite as it actually distorts or resizes the screen. If anyone knows how to create the iAd on top of the view, like sprite, please add a comment or solution.
EDIT
I have just figured out that one can add an ADBannerView to the viewcontroller in the interface builder, this will show the ad on all scenes. I am now trying to figure out how this can be set to not display on specific scenes seeing spritekit only uses one viewcontroller.
If you add the ad by adding in the AdBannerView then you have to create seperate methods in the view controller to turn the ads on or off, by creating these seperate methods it allows one to have manual control over the ads in the view controller from any scene.
In the view controller you have a scene that you create, this scene variable/object has a property of tag or userdata. So if your game goes to a different scene you can call
[super scene] setTag:x]
Every time that the NSTimer calls my control method it checks the value of the scenes tag in the view controller and based on that value it will remove or re-display the ad.
Just a thought, but you could also put the AdBannerView in via the Storyboard editor, and then set
self.canDisplayBannerAds = NO;
That way it will just overlay the SKScene instead of shrinking it.
Hope this helps!
There is another way to fix this problem. You might want to have a look at this Thread.
iAd in Spritekit
Just a sneak preview:
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.delegate = self;
[adView setFrame:CGRectMake(0, 0, 1024, 768)]; // set to your screen dimensions
[adView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:adView];
I want to support landscape & portrait orientations on my iPAD app that uses a storyboard without getting involved into the intricacies of Auto Layout on iOS6+ and Auto Resizing on iOS 5 and earlier (since the app will support both iOS 5 & 6 so no AutoLayout is allowed here), what I thought of as a beginning point for the solution was the following:
creating two separate storyboards: MainStoryboard-Portrait & MainStoryboard-Landscape, when the current view controller (let's name it FirstViewController) is in portrait, and the user rotates the device to landscape, I instantiate a new FirstViewController from MainStoryboard-Landscape storyboard, and vice versa when the user rotates back to portrait. I did something like this in willRotateToInterfaceOrientation method in FirstViewController.m :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard-Landscape" bundle:[NSBundle mainBundle]];
FirstViewController *VC = [storyboard instantiateViewControllerWithIdentifier:#"VC1"];
self.view = VC.view;
but the following crash happens on iOS6+: A view can only be associated with at most one view controller at a time!, tried it also on iOS5 there will be no crash but the rotation does not work properly: window bounds rotates but the view itself keeps as is.
How to get this working on both iOS 5 & 6 ? or if there is another better method please provide me with a working code sample for it and i will award you a bounty of 50 points.
if you really don't wish to use auto layout, doing this in a single .storyboard can still be done by having an IBOutlet (weak, nonatomic) UIView* portraitView and an IBOutlet (weak, nonatomic) UIView* landscapeView. create each view as a subview of the main view for FirstViewController in .storyboard.
then in willRotateToInterfaceOrientation:, perform the following:
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation))
{
self.portraitView.hidden = NO;
self.landscapeView.hidden = YES;
}
else
{
self.portraitView.hidden = YES;
self.landscapeView.hidden = NO;
}
when working on your views in .storyboard, you can see each subview a little better by checking/unchecking the hidden flag in the right sidebar.
then, another advantage of this is that if you have some views that look ok regardless of orientation, you don't have to maintain a separate storyboard file and scene for them.
Auto layout really is the way to go. As soon as you've got two storyboards you've got a maintenance and consistency headache — if you want the portrait and landscape user experience to be the same. If you specifically want them to be different for a reason, then two storyboards is appropriate.
I'm trying to get voice over working with an openGL view, specifically from the cocos2d framework.
From the Apple Accessibility guide I followed this section: Make the Contents of Custom Container Views Accessible
I've subclassed the view (CCGLView for cocos2d people), which is a UIView, to implement the informal UIAccessibilityContainer protocol.
UIAccessibilityContainer implementation in my subclassed UIView:
-(NSArray *)accessibilityElements{
return [self.delegate accessibleElements];
}
-(BOOL)isAccessibilityElement{
return NO;
}
-(NSInteger)accessibilityElementCount{
return [self accessibilityElements].count;
}
-(NSInteger)indexOfAccessibilityElement:(id)element{
return [[self accessibilityElements] indexOfObject:element];
}
-(id)accessibilityElementAtIndex:(NSInteger)index{
return [[self accessibilityElements] objectAtIndex:index];
}
This code is getting called and -(NSArray *)acessibilityElements is returning an array of UIAccessibilityElements. However the voice over controls are not showing up when I touch the screen. Any ideas on what I'm missing or doing wrong?
Other Information:
I'm using a storyboard and adding the CCGLView to the UIView in the storyboard. The _director.view is the CCGLView that I subclassed.
// Add the director as a child view controller.
[self addChildViewController:_director];
// Add the director's OpenGL view, and send it to the back of the view hierarchy so we can place UIKit elements on top of it.
[self.view addSubview:_director.view];
[self.view sendSubviewToBack:_director.view];
For a while I suspected that because I added the subview that this was causing it not to show up, but I also tried subclassing the UIView in the storyboard the same way but it was also not working.
Also this is how I am creating each UIAccessibilityElement in the array.
UIAccessibilityElement *elm = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:view];
elm.accessibilityFrame = f;
elm.accessibilityLabel = t.letter;
elm.isAccessibilityElement = YES;
elm.accessibilityHint = #"Button";
elm.accessibilityValue = t.letter;
elm.accessibilityTraits = UIAccessibilityTraitButton;
Found a solution that is working now, in case anyone has this problem. -(id)accessibilityElementAtIndex:(NSInteger)index was returning a properUIAccessibilityElement but it looks like it wasn't getting retained by whatever Accessibility API is using it. I made a strong NSArray property to hold the UIAccessibilityElements and now it is working fine.
I just came across a crash showing a NSInvalidArgumentException with this message on an app which wasn't doing this before.
Application tried to present modally an active controller
UITabBarController: 0x83d7f00.
I have a UITabBarController which I create in the AppDelegate and give it the array of UIViewControllers.
One of them I want to present modally when tapped on it. I did that by implementing the delegate method
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
If that view controller is of the class of the one I want to present modally, I return NO and do
[tabBarController presentModalViewController:viewController animated:YES];
And now I'm getting that error, which seems to mean that you can't present modally a view controller that is active somewhere else (in the tabbar...)
I should say I'm on XCode 4.2 Developer Preview 7, so this is iOS 5 (I know about the NDA, but I think I'm not giving any forbidden details). I currently don't have an XCode installation to test if this crashes compiling against the iOS4 SDK, but I'm almost entirely sure it doesn't.
I only wanted to ask if anyone has experienced this issue or has any suggestion
Assume you have three view controllers instantiated like so:
UIViewController* vc1 = [[UIViewController alloc] init];
UIViewController* vc2 = [[UIViewController alloc] init];
UIViewController* vc3 = [[UIViewController alloc] init];
You have added them to a tab bar like this:
UITabBarController* tabBarController = [[UITabBarController alloc] init];
[tabBarController setViewControllers:[NSArray arrayWithObjects:vc1, vc2, vc3, nil]];
Now you are trying to do something like this:
[tabBarController presentModalViewController:vc3];
This will give you an error because that Tab Bar Controller has a death grip on the view controller that you gave it. You can either not add it to the array of view controllers on the tab bar, or you can not present it modally.
Apple expects you to treat their UI elements in a certain way. This is probably buried in the Human Interface Guidelines somewhere as a "don't do this because we aren't expecting you to ever want to do this".
I have the same problem. I try to present view controller just after dismissing.
[self dismissModalViewControllerAnimated:YES];
When I try to do it without animation it works perfectly so the problem is that controller is still alive. I think that the best solution is to use dismissViewControllerAnimated:completion: for iOS5
In my case i was trying to present the viewController (i have the reference of the viewController in the TabBarViewController) from different view controllers and it was crashing with the above message.
In that case to avoid presenting you can use
viewController.isBeingPresented
!viewController.isBeingPresented {
// Present your ViewController only if its not present to the user currently.
}
Might help someone.
The same problem error happened to me when I tried to present a child view controller instead of its UINavigationViewController parent
I had same problem.I solve it. You can try This code:
[tabBarController setSelectedIndex:1];
[self dismissModalViewControllerAnimated:YES];
For React Native Developer - Problem might not be in AppDelegate Or main.m if app has been successfully build and is running and will crash after splash or perhaps the error screen
Issue might be due to use of fonts/resources that is not available with xcode and not properly configured.. You can find out the error by commenting certain portion starting from App.js and drilling inside the navigation/screens and commenting the components till you find the component that is generating the error....
In my case the resource of fontFamily was making an issue which was used right after splash in walkthrough screen
<Text style={{fontFamily: Fonts.roboto}}>ABC</Text>
Here font roboto wasnot configured properly. Wasted entire days just debugging the error hope its helps you
In my case, I was presenting the rootViewController of an UINavigationController when I was supposed to present the UINavigationController itself.
Just remove
[tabBarController presentModalViewController:viewController animated:YES];
and keep
[self dismissModalViewControllerAnimated:YES];
Instead of using:
self.present(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)
you can use:
self.navigationController?.pushViewController(viewController: UIViewController, animated: Bool)
This is my way which supporting multiple Windows(from a single APP) on the iPad and nested modal present.
import UIKit
///✅Use this public method
public func SheetViewController(ViewController:UIViewController) {
for i in returnAvailableViewControllers().shuffled() {
if i.presentedViewController == nil && !ViewController.isViewLoaded {i.present(ViewController, animated: true, completion: {})}
}
}
///Returns all possible ViewControllers
private func returnAvailableViewControllers() -> [UIViewController] {
let 场景 = UIApplication.shared.connectedScenes
var 存储VC : [UIViewController] = []
for i in 场景 {
if i.activationState == .foregroundActive {
//⭐️Set up “foregroundActive” to give the user more control
var 视图控制器 = (i.delegate as? UIWindowSceneDelegate)?.window??.rootViewController
if 视图控制器 != nil {
存储VC.append(视图控制器!)
}
var 结束没 = true
while 结束没 {
//🌟Enumerate all child ViewController
视图控制器 = 视图控制器?.presentedViewController
if 视图控制器 != nil {
存储VC.append(视图控制器!)
} else {
结束没.toggle()
}
}
}
}
return 存储VC
}
My question starts from a problem :
I started a project in Xcode : a Navigation Bar based one (with a TableView).
Then I added a few views, through IB or programmatically... which works perfectly fine.
Then, I decided to write my Own ViewClass, inherited from UIView, called OpenGlView (based on the view provided by Basic OpenGlES project in XCode), and its OpenGlViewController (inherited from UIViewController).
This works fine until I try to push the view Controller into my navBar: then I receive a "EXC__ BAD __ACCESS". I can't understand why it is ok whith any view but the one used for display OpenGL content...
And I actually have no idea how I can manage to develop a NavBar based App including a View displaying OpenGL contents... any idea?
(I also tried to add the OpenGlView as a subView of a basic UIView previously added to the NavigationBar, but I received the same error).
In the RootController :
OpenGlViewController *glvController;
if (glvController == nil)
{
glvController = [[OpenGlViewController alloc] initWithNibName:#"Gl View" bundle:nil];
glvController.title = #"GL View";
}
[self.navigationController pushViewController:glvController animated:YES];
in the OpenGlViewController :
- (void)loadView {
OpenGlView * view;
view = [[OpenGlView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = view;
[view release];
}
If it's localized to your OpenGL view, the crash may be the result of not properly initializing OpenGL items inside your view. See here for my recommendations on a potentially similar problem.