如何从SKScene呈现UIViewController?

时间:2013-10-17 22:57:38

标签: ios objective-c uiview uiviewcontroller sprite-kit

我通过Sprite Kit进入iOS,我认为这是不明智的。

我的目标是在游戏结束时显示“分享”按钮。点击共享按钮应该呈现SLComposeViewController(Twitter Share)。场景的内容不应该改变。

决定“游戏结束”的游戏逻辑存在于SpriteMyScene.m中,这是SKScene的子类。

我可以通过这种方式在游戏中显示分享按钮:

-(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];
}

我遇到的问题是试图让showTweetButton方法起作用。我的SpriteViewController.m看起来像这样:

- (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.");
    }];
}

我总是在日志中得到这样的东西:

  

- [UIView presentScene:]:无法识别的选择器发送到实例0x13e63d00 2013-10-17 18:40:01.611修复[33409:a0b] * 终止应用   由于未捕获的异常'NSInvalidArgumentException',原因:   ' - [UIView presentScene:]:无法识别的选择器发送到实例   0x13e63d00'

5 个答案:

答案 0 :(得分:11)

您正在创建一个新的视图控制器,但从未提供它:

SpriteViewController *viewController = [SpriteViewController alloc];

我假设SpriteViewController是您SpriteMyScene的内容,并且您希望将控制权交还给呈现SpriteViewController

您需要在SpriteViewController子类中保留对SpriteMyScene的引用,然后在致电openTweetSheet时访问该引用。

在SpriteMyScene.h中

@class SpriteViewController;

@interface SpriteMyScene : SKScene

@property (nonatomic, weak) SpriteViewController *spriteViewController;

@end
SpriteViewController.m中的

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

myScene.spriteViewController = self;
SpriteMyScene.m中的

#import "SpriteViewController.h"

- (void)sendToController
{
    NSLog(@"ok");
    // use the already-created spriteViewController
    [_spriteViewController openTweetSheet];
}

答案 1 :(得分:4)

您可以使用

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

此代码将为您提供对根视图控制器的访问权限,以便您可以执行任何操作,您的视图控制器就像正常一样。

但是,你需要添加一个按钮吗?在这种情况下,使用精灵并向其添加事件会更好。请致电:

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

并且

-(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];
        }
    }
}

答案 2 :(得分:3)

如果要从场景中打开另一个UIViewController,则必须首先在最初创建此场景的主View Controller中创建一个委托,以便场景可以通知​​其ViewController一个打开的推文动作。您将需要以下步骤:

  1. 在主视图控制器中定义委托 - 我们场景的视图控制器,用于处理打开的推文操作。
  2. 在主View Controller中实施委托方法
  3. 在场景中添加一个委托属性,以便它可以保持其ViewController的委托方法实现的句柄。在创建场景期间将此委托设置为主视图控制器
  4. 检测场景中的事件以调用主ViewController的委托方法
  5. 在委托方法实现中将控件传递给TweetSheetViewController
  6. 以下是示例:

    @protocol ViewControllerDelegate <NSObject>
    -(void) openTweetSheet;
    @end
    

    扩展此ViewController以在其.h文件中支持此协议

    @interface ViewController : UIViewController<ViewControllerDelegate>
    
    @end
    

    然后在.m文件中实现协议中的方法

    -(void) openTweetSheet{
        TweetSheetViewController *ctrl = [[TweetSheetViewController alloc] initWithNibName:@"TweetSheetViewController" bundle:nil];
    
        [self presentViewController:ctrl animated:YES completion:nil];
    }
    

    在Scene头类中,添加委托属性

    @interface MyScene : SKScene {
    
    }
    @property (nonatomic, weak) id <ViewControllerDelegate> delegate;
    
    @end
    

    在ViewController中,在呈现场景之前,在viewDidLoad方法中设置其委托:

    // Create and configure the scene.
    MyScene * scene = [MyScene sceneWithSize:skView.bounds.size];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    
    [scene setDelegate:self];
    // Present the scene.
    [skView presentScene:scene];
    

    现在您的Scene可以将消息传递回ViewController,ViewController可以打开另一个ViewController。在场景类中,确定将触发打开TweetSheetViewController

    的操作
    -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        /* Called when a touch begins */
    
        for (UITouch *touch in touches) {
            CGPoint location = [touch locationInNode:self];
            SKAction *fadeOut = [SKAction fadeOutWithDuration:0.5];
            SKAction *fadeIn = [SKAction fadeInWithDuration:1.0];
            SKAction *sequence = [SKAction sequence:@[fadeOut,fadeIn]];
    
            SKNode *node = [self nodeAtPoint:location];
            if ([[node name]  isEqual: @"openTweet"]) {
                NSLog(@"help");
                [node runAction:sequence];
                [delegate openTweetSheet];
            }
    
    }
    

    希望有所帮助。

答案 3 :(得分:1)

将SlComposeViewController方法写入您希望它发生的场景中。例如:

@interface GameOverScene: SKScene

...initwithsize bla bla bla
...

添加以下方法:

-(void)OpenTweetShet{

    if ([SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]) {

    _composeTwitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
    [_composeTwitter setInitialText:@"TWEET"];

然后致电:

self.view.window.rootViewController **to present the SLComposeViewController**

    [self.view.window.rootViewController presentViewController:_composeTwitter animated:YES completion:nil];


}

[_composeTwitter setCompletionHandler:^(SLComposeViewControllerResult result){

NSString *output =[[NSString alloc]init];

switch (result) {
    case SLComposeViewControllerResultCancelled:
        output = @"Post cancelled";
        break;
    case SLComposeViewControllerResultDone:
        output = @"Post Succesfull";
        break;
    default:
        break;      
    }

以下是发送/取消后发布UIAlert的选项:

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Twitter" message:output delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
    [alert show];     
    }];
}
@end

答案 4 :(得分:0)

这对我有用:self.view.window.rootViewController

-(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;
        [self.view.window.rootViewController openTweetSheet];
    }
}
}