Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I present a UIViewController from SKScene?

I'm entering iOS via Sprite Kit, which I recognize is unwise.

My goal is to display a "Share" button upon Game Over. Tapping the share button should present a SLComposeViewController (Twitter Share). The contents of the scene should not change.

The game logic that dictates "Game Over" lives in SpriteMyScene.m, a subclass of SKScene.

I'm able to display a Share button on Game Over this way:

-(void)update:(CFTimeInterval)currentTime {

if (gameOver){
  UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
                [button addTarget:self
                           action:@selector(sendToController)
                forControlEvents:UIControlEventTouchDown];
                [button setTitle:@"Show View" forState:UIControlStateNormal];
                button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
                [self.view addSubview:button]; 
    }
}

- (void)sendToController
{
    NSLog(@"ok");
    SpriteViewController *viewController = [SpriteViewController alloc];
    [viewController openTweetSheet];
}

Where I get stuck is trying to get the showTweetButton method to work. My SpriteViewController.m looks like this:

- (void)openTweetSheet
    {
     SLComposeViewController *tweetSheet = [SLComposeViewController
                                           composeViewControllerForServiceType:
                                           SLServiceTypeTwitter];

    // Sets the completion handler.  Note that we don't know which thread the
    // block will be called on, so we need to ensure that any required UI
    // updates occur on the main queue
    tweetSheet.completionHandler = ^(SLComposeViewControllerResult result) {
        switch(result) {
                //  This means the user cancelled without sending the Tweet
            case SLComposeViewControllerResultCancelled:
                break;
                //  This means the user hit 'Send'
            case SLComposeViewControllerResultDone:
                break;
        }
    };

    //  Set the initial body of the Tweet
    [tweetSheet setInitialText:@"just setting up my twttr"];

    //  Adds an image to the Tweet.  For demo purposes, assume we have an
    //  image named 'larry.png' that we wish to attach
    if (![tweetSheet addImage:[UIImage imageNamed:@"larry.png"]]) {
        NSLog(@"Unable to add the image!");
    }

    //  Add an URL to the Tweet.  You can add multiple URLs.
    if (![tweetSheet addURL:[NSURL URLWithString:@"http://twitter.com/"]]){
        NSLog(@"Unable to add the URL!");
    }

    //  Presents the Tweet Sheet to the user
    [self presentViewController:tweetSheet animated:NO completion:^{
        NSLog(@"Tweet sheet has been presented.");
    }];
}

I always get something like this in the logs:

-[UIView presentScene:]: unrecognized selector sent to instance 0x13e63d00 2013-10-17 18:40:01.611 Fix[33409:a0b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView presentScene:]: unrecognized selector sent to instance 0x13e63d00'

like image 762
Nick Barr Avatar asked Oct 17 '13 22:10

Nick Barr


2 Answers

You're creating a new view controller but never presenting it:

SpriteViewController *viewController = [SpriteViewController alloc];

I'm assuming that SpriteViewController is what presents your SpriteMyScene, and you'd like to hand control back to the presenting SpriteViewController.

You need to keep a reference to SpriteViewController in your SpriteMyScene subclass, and then access that reference when you call openTweetSheet.

in SpriteMyScene.h

@class SpriteViewController;

@interface SpriteMyScene : SKScene

@property (nonatomic, weak) SpriteViewController *spriteViewController;

@end

in SpriteViewController.m

// somewhere you initialize your SpriteMyScene object, I'm going to call it myScene

myScene.spriteViewController = self;

in SpriteMyScene.m

#import "SpriteViewController.h"

- (void)sendToController
{
    NSLog(@"ok");
    // use the already-created spriteViewController
    [_spriteViewController openTweetSheet];
}
like image 98
paulrehkugler Avatar answered Oct 08 '22 21:10

paulrehkugler


You can use

UIViewController *vc = self.view.window.rootViewController;

This code will give you the access to your root View controller so you can do anything you do will your view controller like normal.

However, do you need to add a button? Use a sprite and add an event to it is better for you in this case. Just call:

UIViewController *vc = self.view.window.rootViewController;
[vc openTweetSheet];

And

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
    for (SKNode *node in nodes) {
        if ([node.name isEqualToString:@"OpenTweet"]) {
            UIViewController *vc = self.view.window.rootViewController;
            [vc openTweetSheet];
        }
    }
}
like image 43
Huygamer Avatar answered Oct 08 '22 20:10

Huygamer