ERROR: whose view is not in the window hierarchy. Spritekit - ios

I will try to explain this best i can. Okay i am using SpriteKit in xcode5. Inside Myscene.m i have a method called:
-(void)presentViewController
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"MyView"];
[self.view.window.rootViewController presentViewController:vc animated:YES completion:nil];
}
Then in my NSTimeintervalUpdate method i have a code that says
if(score >= 3)
{
[self presentViewController]
}
All this code brings up the view controller i want from the storyboard like it should with no problems but in this view controller it has a button that links up back to the game. When you click the button it goes right back to the game like it should. Well during the game instead of going back to my ViewController at a score of "3" like it did the first time, it just continues to count up and provides the following error message in the log:
2014-07-12 22:40:27.710 tests[337:60b] Warning: Attempt to present <ViewController2: 0xc354e40> on <ViewController: 0x9960b80> whose view is not in the window hierarchy!
My intention is to have my game (Myscene.m) and when the game is over is to have a game over screen (ViewController). And then from this view controller i want it to have a play again button that is linked back to Myscene.m(which i simply did by making button and control and drag to the view controller that handles my SKScene) and continues to repeat process but it will only do this process once and then it fails to loop back around and instead presents the above error.
Any help appreciated thanks!

Don't present View Controller from SKScene directly. Use NSNotificationCenter to tell parent View Controller to present another View Controller:
In GameSceneViewController.m:
#interface GameSceneViewController
#property (nonatomic) int score;
#end
#implementation GameSceneViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(presentMyViewController:) name:#"presentMyViewController" object:nil];
}
- (void)presentMyViewController:(NSNotification *)notification {
self.score = notification.userInfo[#"score"];
[self performSegueWithIdentifier:(segue identifier) sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:(segue identifier])
{
// Get reference to the destination view controller
MyViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
vc.score = self.score;
}
}
#end
Then in GameScene.m call:
[[NSNotificationCenter defaultCenter] postNotificationName:#"presentMyViewController" object:nil userInfo:#{"score" : self.score}];

Related

Transfer data between view controllers, using storyboard and TabBarController

I have a Login ViewController and a Tab Bar Controller with two “tabs”. Now I want to transfer data from Login VC to one of the TabBar VCs. If the Login VC receives certain information, it should call a method in one of the TabBar VCs. I created all the view controllers with the storyboard. I don’t use programmatically segue of the view controllers.
Thus I tried to use a protocol and delegate. But when I’m coding something like this:
LoginViewController *loginVC = [[LoginViewController alloc] init];
loginVC.myTestDelegate = self;
It creates a new instance of the view controller and didn’t take the existing where it gets the information to call the method.
Is there any way to fix that problem? Or do I have to use programmatically segues?
If yes how can I change the tabs programmatically?
YourViewController* pdvc = [[YourViewController alloc] init];
pdvc.selectedImage = selectedPhoto;
pdvc.selectedObj = theObject;
pdvc.selectedImg = theImage;
[self presentViewController:pdvc animated:YES completion:nil];
or
YourViewController* nextView = [self.storyboard
instantiateViewControllerWithIdentifier:
#"YOUR_NEXT_STORYBOARD_ID"];
[nextView setYOUR_VALUE:value];
[self presentViewController:nextView
animated:YES
completion:nil];
If you want to navigate to the same viewController to which you want to pass data when your loginViewController receives data, then you can use following method which is triggered when the transition begins from the current view.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"yourViewIdentifier"]) {
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recievingData = yourDataToPass;
}
}
Second method is to add observers using NSNotificationCenter class:
Add following method to your TabBar VCs in viewDidLoad: method
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(viewDidReceivedData:)
name:"ReceivedData" object:nil];
And implement following method:
- (void)viewDidReceivedData:(id)receivedData{
}
In your loginViewController,once you receive necessary information to pass to the viewcontroller call following:
[[NSNotificationCenter defaultCenter] postNotificationName:#"ReceivedData" object:yourData];
Refer: http://www.hpique.com/2013/12/nsnotificationcenter-part-1/

Is there any way to push a vc in a storyboard in init with coder?

So I have a problem when trying to push some Viewcontrollers basically when the app loads it checks if you are already registered and if you are it sends you to a diff vc and if your not registered it sends you to a RegisterVC. It's done in storyboard and the problem is that when I put the code in viewDidLoad the pushes works but I can't see the rootviewcontroller from the storyboard but if I move the code into the init with coder I can see the viewcontroller but the push return's nil in the method that's supposed to push to a new vc, so the transition never happens.
The code looks like follows:
if (emp == nil) {
[self gotoRegisterView];
}
else {
[self gotoSMWView];
}
and :
- (void) gotoRegisterView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"RegisterVC"];
[self.navigationController pushViewController:vc animated:YES];
}
- (void) gotoSMWView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SMWVC"];
[self.navigationController pushViewController:vc animated:YES];
}
Any suggestions are much appreciated.
If you're using storyboards, just connect the main scene to any other scene you want to call from there. Then, Ctrl+Drag from the initial VIEW CONTROLLER (not elements on the view controller, but from the controller itself). Then click on the segues you just created and give them good descriptive names. For this example, we'll just say segue1 and segue2.
Now, if segue1 takes you to the RegisterView, and segue2 to SMWView then you can do this:
- (void) gotoRegisterView {
[self performSegueWithIdentifier:#"segue1" sender:self];
}
- (void) gotoSMWView {
[self performSegueWithIdentifier:#"segue2" sender:self];
}
If you need to do any other initialization or set up on these view controllers, you can override this method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Within this method, you can check which segue has been called using this template:
if([[segue identifier] isEqualToString:#"segue1"])
And you can get an instance of your destination view controller like this:
YourViewController *vc = [segue destinationViewController];

iOS navigationController pushViewController not working

I have a storyboard with a UINavigationController. The root view controller of the navigation controllers is called rootViewController.
I am trying to programmatically change the view controller (depending on other conditions) to another view controller called loginViewController.
I am trying to do this in the viewDidLoad from the rootViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
loginViewController *viewController = [[loginViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
}
I am not getting any errors but it's not working.
It just loads the navigation controller with the top nav back button but the rest of the screen is black. It's like it's not loading any view controller.
I am trying to figure out what I am doing wrong.
Any help with this would be great.
Thanks
First add loginViewController class in storyboard and and connect ViewController class to loginViewController class and give identifier name as "identifier_Name".
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSegueWithIdentifier:#"identifier_Name" sender:nil];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"identifier_Name"])
{
loginViewController *viewController = [segue destinationViewController];
}
}
If you're using storyboard, create your login view in the storyboard, link your rootVC to the loginVC with a segue, choose an identifier (for example: "goToLogin"). and then to go in the login view, and use:
[self performSegueWithIdentifier:#"goToLogin" sender:self];

Delegation in Xcode

When the user pressed an 'add' button a modal view pops up for them to enter information. I have a 'cancel' button in the top left of a navigation bar and I want it to dismiss the current view controller when it is pressed. How do I set an object as the class's delegate? I understand creating protocols and implementing its methods but I cannot seem to make the delegate be set. When running the debugger my [self delegate] in the 'add' view controller is always nil.
Are you spawning the modal viewController through a segue set up in your Storyboard? If so, then in the prepareForSegue: method you would set the delegate there.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([identifier isEqualToString:#"userGuideSegue_home"]){
UserGuideViewController* vc = segue.destinationViewController;
[[segue destinationViewController] setDelegate:self];
}
}
On the other hand, if you are setting up the modal viewController entirely through code, then you would create an instance of the modal viewController then set it's delegate.
- (void)showModelView:(NSString*)viewName
{
// code ripped out of project so a bit specific
if ([viewName isEqualToString:#"userGuide_name"]) {
modalViewController = (UserGuideViewController * )
[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:NULL]
instantiateViewControllerWithIdentifier:#"UserGuide"];
}
modalViewController.delegate = self;
modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
modalViewController.view.frame = [[UIScreen mainScreen] applicationFrame];;
[self presentViewController:modalViewController
animated:YES
completion:^{
//put your code here
}];
}
Of course all this assumes you have defined a delegate property on your modal viewController.
If you created the view in IB, Control-drag the button into the ViewController's header file and add an IBOutlet. Inside of that method in the .m file you can
[self dismissModalViewControllerAnimated:YES];
alternatively you can create the button programmatically:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(processCancel:)];
-(void)processCancel:(UIBarButtonItem *)item{
[self dismissModalViewControllerAnimated:YES];
}
#interface MyViewController : UIViewController {
id delegate;
}
#property (nonatomic,retain) id delegate;
#synthesize delegate;
This should do the job, you can now use [MyViewController setDelegate:self] before showing the modal view and call [[self delegate] dismissModalViewControllerAnimated:YES] in the cancel button tapped event in MyViewController

Receive a ViewDidUnload message through UINavigationControllerDelegate

DetailViewController <-> MasterViewController <-> ViewController
At the moment I solve my problem by having a variable in the ViewController class point to the DetailViewController so that I can perform a method when the DONE button in ViewController is pressed.
- (void)doneButtonPressed {
[self.detailViewController method];
}
What I want to do is to have the ViewController report to DetailViewController when it unloads, so that DetailViewController can perform the method itself.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[self.navigationController delegate] performSelector:#selector(method)];
}
What I have tried is to have the MasterViewController set the ViewControllers delegate to DetailViewController with this code, when it is pushed:
ViewController *ViewController = [[ViewController alloc] init];
ViewController.navigationController.delegate = self.detailViewController;
[self.navigationController pushViewController:ViewController animated:YES];
UINavigationControllerDelegate has been set in DetailViewController.
What am I doing wrong?
My question was badly formulated.
The answer is in the documentation:
View Controller Programming Guide for iOS
-> Modal View Controllers
Dismissing a Modal View Controller
http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html#//apple_ref/doc/uid/TP40007457-CH111-SW14

Resources