iOS.Lover
iOS.Lover

Reputation: 6051

Presenting UIViewController from SKScene

I am trying to present a UIViewController from SKScene but, app crashes , here is my codes :

1- :

 UIViewController *vc = self.view.window.rootViewController;
    helpVC = [[HelpViewController alloc]initWithNibName:@"HelpViewController" bundle:nil];
    [vc presentViewController: helpVC animated: YES completion:nil];

2-

   helpVC = [[HelpViewController alloc]initWithNibName:@"HelpViewController" bundle:nil];
    SKScene *sks = (SKScene*)helpVC;
    [self.view presentScene:sks];

in both ways my app crashes , thanks for any help

crashes due to :

2014-02-08 16:38:29.119 BrickRacer[13883:70b] -[UIView presentScene:]: unrecognized selector sent to instance 0x10bb7ea50
2014-02-08 16:38:29.122 BrickRacer[13883:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView presentScene:]: unrecognized selector sent to instance 0x10bb7ea50'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000101fe8795 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000101d4b991 objc_exception_throw + 43
    2   CoreFoundation                      0x0000000102079bad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x0000000101fda09d ___forwarding___ + 973
    4   CoreFoundation                      0x0000000101fd9c48 _CF_forwarding_prep_0 + 120
    5   BrickRacer                          0x000000010000bb6d -[ViewController viewDidLoad] + 317
    6   BrickRacer                          0x000000010000b996 -[HelpViewController viewDidLoad] + 54
    7   UIKit                               0x0000000100971fe4 -[UIViewController loadViewIfRequired] + 562
    8   UIKit                               0x00000001009721bd -[UIViewController view] + 29
    9   UIKit                               0x000000010097f03f -[UIViewController viewControllerForRotation] + 54
    10  UIKit                               0x0000000100977f5f -[UIViewController _visibleView] + 87
    11  UIKit                               0x0000000100bb7f89 -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:animation:] + 4550
    12  UIKit                               0x000000010097c579 -[UIViewController presentViewController:withTransition:completion:] + 4769
    13  BrickRacer                          0x000000010001c6a9 -[Menu help] + 521
    14  BrickRacer                          0x000000010001c43a -[Menu touchesBegan:withEvent:] + 554
    15  SpriteKit                           0x00000001017d8712 -[SKView touchesBegan:withEvent:] + 611
    16  UIKit                               0x00000001008bba84 -[UIWindow _sendTouchesForEvent:] + 300
    17  UIKit                               0x00000001008bc633 -[UIWindow sendEvent:] + 988
    18  UIKit                               0x0000000100895fa2 -[UIApplication sendEvent:] + 211
    19  UIKit                               0x0000000100883d7f _UIApplicationHandleEventQueue + 9549
    20  CoreFoundation                      0x0000000101f77ec1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    21  CoreFoundation                      0x0000000101f77792 __CFRunLoopDoSources0 + 242
    22  CoreFoundation                      0x0000000101f9361f __CFRunLoopRun + 767
    23  CoreFoundation                      0x0000000101f92f33 CFRunLoopRunSpecific + 467
    24  GraphicsServices                    0x0000000102abe3a0 GSEventRunModal + 161
    25  UIKit                               0x0000000100886043 UIApplicationMain + 1010
    26  BrickRacer                          0x000000010000ea93 main + 115
    27  libdyld.dylib                       0x0000000104ab15fd start + 1
    28  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Upvotes: 0

Views: 3304

Answers (3)

Nir Golan
Nir Golan

Reputation: 1336

Your problem is twofold:

  1. Casting a UIViewController to SKScene.
    SKScene *sks = (SKScene*)helpVC;
    Casting should be done in other scenarios : e.g. between primitives, between UI Foundation and CF classes or between a subclass and it's super (but shouldn't be done in the opposite way!).
    Long story short - not in this scenario (these classes have nothing in common)

  2. You ask your view to present a scene, but pass a viewController instead :
    [self.view presentScene:sks];
    So, what happened here ?
    presentScene: thinks they got an SKScene object, thus sends some message to sks. A message that sks does not understand... and crashes.

How to solve this ?

Grab your presenting view controller.
Either in a global, or just grab your root view controller from the app delegate:

UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootVC presentViewController:yourPresentedVC animated:YES completion:nil];

In case you're using a tab bar/navigation controller you should grab their presented VC.

Upvotes: 2

Andrey Gordeev
Andrey Gordeev

Reputation: 32449

Don't try to present UIViewController from SKScene directly, this breaks MVC pattern. SKScene is part of View, View should not know anything about ViewController.

Instead, you can use NSNotificationCenter to notify SKScene's UIViewController that it should present another UIViewController:

In SKScene's UIViewController:

- (void)awakeFromNib {
    [[NSNotificationCenter defaultCenter] 
        addObserver:self
        selector:@selector(goToGameOverViewController:)
        name:@"GoToGameOverViewController"
        object:nil];
}

.

-(void)goToGameOverViewController:(NSNotification *) notification {
    // Perform a segue or present ViewController directly
    //[self performSegueWithIdentifier:@"GameOverSegue" sender:self];
    HelpViewController *helpVC = [[HelpViewController alloc]initWithNibName:@"HelpViewController" bundle:nil];
    [self presentViewController:helpVC animated: YES completion:nil];
}

.

- (void) dealloc
{
    // If you don't remove yourself as an observer, the Notification Center
    // will continue to try and send notification objects to the deallocated
    // object.
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

In SKScene:

- (void)gameOver {
    [[NSNotificationCenter defaultCenter]
         postNotificationName:@"GoToGameOverViewController" object:self];
}

Upvotes: 8

Johnykutty
Johnykutty

Reputation: 12819

Try

UIViewController *vc = [[UIApplication sharedApplication] keyWindow].rootViewController;
helpVC = [[HelpViewController alloc]initWithNibName:@"HelpViewController" bundle:nil];
[vc presentViewController: helpVC animated: YES completion:nil];

Upvotes: 1

Related Questions