Как представить UIViewController из SKScene?

Я вхожу в iOS через Sprite Kit, который я признаю неразумным.

Моя цель - отобразить кнопку "Поделиться" при игре. При нажатии кнопки общего доступа должен присутствовать 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

Ответ 1

Вы создаете новый контроллер представления, но не представляете его:

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

Ответ 2

Вы можете использовать

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

Ответ 3

Если вы хотите открыть другой UIViewController внутри вашей сцены, вам сначала нужно создать делегат в основном контроллере просмотра, который изначально создавал эту сцену, чтобы ваша сцена могла уведомить свой ViewController о действии открытого твита. Вам понадобятся следующие шаги:

  • Определите делегата в основном контроллере представления - контроллере представления нашей сцены, чтобы обработать открытое действие твита.
  • Реализация метода делегата в основном контроллере представления
  • Добавить свойство делегата в вашей сцене, чтобы он мог сохранить дескриптор реализации метода делегирования ViewController. Установите этот делегат в качестве основного контроллера просмотра во время создания сцены.
  • Обнаружение события на сцене для вызова метода делегата основного ViewController
  • В реализации метода делегата передайте элемент управления TweetCheetViewController

Вот пример:

@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];

Теперь ваша сцена может передать сообщение обратно в 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];
        }

}

Надеюсь, что это поможет.

Ответ 4

Напишите метод 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 после сообщения send/cancel:

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

Ответ 5

Это сработало для меня: 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];
    }
}
}