Present another View Controller from SkScene - sprite-kit

I'm trying to present another viewController from my "SkScene".
This is my main viewController(tuViewController)
Code:
-(void) openTweetSheet{
FacebookLikeViewDemoViewController *ctrl = [[FacebookLikeViewDemoViewController alloc] initWithNibName:#"FacebookLikeViewDemoViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
This is my "SkScene":
tuViewController *viewController = [[tuViewController alloc]init];
[viewController openTweetSheet];
And the viewController which i want to present is FacebookLikeViewDemoViewController and i need to have way back to "SkScene".
And i got sigabrt error, i tried few ways to present viewController but always with failure, one time i got swap to viewController but it was entirely black. I read a lot how to perform that, but i personally can't figure out. I appreciate your help.
I tried too with Notification Center.
Main viewController
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(goToGameOverViewController:)
name:#"GoToGameOverViewController"
object:nil];
-(void)goToGameOverViewController:(NSNotification *) notification {
FacebookLikeViewDemoViewController *helpVC = [[FacebookLikeViewDemoViewController alloc]initWithNibName:#"HelpViewController" bundle:nil];
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootVC presentViewController:helpVC animated:YES completion:nil];
}
SkScene
[[NSNotificationCenter defaultCenter]
postNotificationName:#"GoToGameOverViewController" object:self];
But i got the same error. I prefer to figure out why the way with notification won't work.

I assume by your question that you are looking to do some social media posting.
You can either pass a reference for your View Controller to your SKScene or you can use NSNotificationCenter instead. I prefer to use the latter.
First make sure you have added the Social.framework to your project.
Import the social framework into your View Controller #import <Social/Social.h>
Then in your View Controller's viewDidLoad method add this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(createTweet:)
name:#"CreateTweet"
object:nil];
Next add this method to your View Controller:
-(void)createTweet:(NSNotification *)notification
{
NSDictionary *tweetData = [notification userInfo];
NSString *tweetText = (NSString *)[tweetData objectForKey:#"tweetText"];
NSLog(#"%#",tweetText);
// build your tweet, facebook, etc...
SLComposeViewController *mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
At the appropriate location in your SKScene, (won game, lost game, etc...) add this code:
NSString *tweetText = #"I just beat the last level.";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:tweetText forKey:#"tweetText"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreateTweet" object:self userInfo:userInfo];
The above code sends a NSNotification, with text, which your View Controller will pick up and execute the specified method (which is createTweet in the above example).

Related

Posting score to facebook

I created an app in SpriteKit with xcode where when the game is over, it shows you your score, and I want to add the feature to post your score to facebook. Pretty much all my code is in MyScene.m where it can't access presentViewController. Only my ViewController.m file can access that, so I tried calling a instance method in Viewcontroller from Myscene.m but I can't find a way to do that. The only way I have found calling methods from other files is using +(void) which is a class method I think.
Myscene.m:
if (location.x < 315 && location.x > 261 && location.y < 404 && location.y > 361) {
//if you click the post to facebook button (btw, location is a variable for where you tapped on the screen)
[ViewController facebook];
}
ViewController.m:
+(void)facebook{
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *facebook = [[SLComposeViewController alloc] init];
facebook = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[facebook setInitialText:#"initial text"];
}
}
So that worked, and it called the facebook class method correctly, but when I put [self presentViewController:facebook animated:YES] after the setInitialText brackets, it gives me this error: No known class method for selector 'presentViewController:animated:'
By the way it lets me use presentViewController in a instance method but I can't call that method from inside the class method or from my Myscene file. Is there any way to either call an instance method from another file, or access presentViewController from a class method? Thanks
You can either pass a reference for your View Controller to your SKScene or you can use NSNotificationCenter instead. I prefer to use the latter.
First make sure you have added the Social.framework to your project.
Import the social framework into your View Controller #import <Social/Social.h>
Then in your View Controller's viewDidLoad method add this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(createPost:)
name:#"CreatePost"
object:nil];
Next add this method to your View Controller:
-(void)createPost:(NSNotification *)notification
{
NSDictionary *postData = [notification userInfo];
NSString *postText = (NSString *)[postData objectForKey:#"postText"];
NSLog(#"%#",postText);
// build your tweet, facebook, etc...
SLComposeViewController *mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
At the appropriate location in your SKScene, (won game, lost game, etc...) add this code:
NSString *postText = #"I just beat the last level.";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:postText forKey:#"postText"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreatePost" object:self userInfo:userInfo];
The above code sends a NSNotification, with text, which your View Controller will pick up and execute the specified method.

ModalViewController not in the window hierarchy

After a long period of trying and searching the Internet and StackOverflow I could not find the answer I need.
My Problem is a warning:
Warning: Attempt to present <PAPasscodeViewController: 0x81cc8a0> on <ServerViewController: 0x75864b0> whose view is not in the window hierarchy!
I am using a Custom Control called "PAPasscodeViewController", the thing itself is working but when I try to display the view on the ApplicationDidBecomeActive method it displays this warning in the Consoleoutput.
I am using this method to keep track of the Notification:
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(wait)
name:UIApplicationDidBecomeActiveNotification object:nil];
my -(void)wait is containing this:
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
NSLog(#"waiting");
[self performSelector:#selector(enterPasscode) withObject:nil afterDelay:.3f];
The App is having a RootViewController and a GeneralViewController, if the User already downloaded a Config package the GeneralViewController gets pushed in after starting as a modalView like this (in the viewDidLoad):
GeneralView = [[GeneralViewController alloc] initWithNibName:#"GeneralViewController" bundle:[NSBundle mainBundle]];
GeneralView.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentViewController:GeneralView animated:YES completion:nil];
In the GeneralView the User has more Options to open new Views through Buttons and they get pushed in through IBActions like the GeneralViewController.
So the Problem is occuring when this happens:
I am starting the App, Config Package was already installed and the User wants to track his ServerData on "ServerViewController", so he touches the appropriate Button for this.
Then the View gets pushed in (its now RootViewController (managed by AppDelegate)-> GeneralViewController(pushed in)-> ServerViewController(pushed in)), everything works fine.
Now when the User goes back to his Homescreen I am closing the modal View "ServerViewController" as follows:
-(void)viewDidAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(close:)
name:UIApplicationDidEnterBackgroundNotification object:nil];}
-(IBAction)close:(id)sender{
[self dismissViewControllerAnimated:YES completion:nil];
}
so when the App enters Backgrounding the ServerViewController gets dismissed, after resuming the App the GeneralViewController is now the active View Controller, and in his -(void)viewDidAppear I am calling the -(void)wait from above, it calls this function:
- (void)enterPasscode{
PAPasscodeViewController *passcodeViewController = [[PAPasscodeViewController alloc] initForAction:PasscodeActionEnter];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
passcodeViewController.backgroundView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
}
passcodeViewController.delegate = self;
passcodeViewController.passcode = [configArray objectAtIndex:3];
passcodeViewController.simple = YES;
[self presentViewController:passcodeViewController animated:YES completion:nil];
}
This is working fine but then I am getting the annoying warning from above (here again so you dont have to scroll up)
Warning: Attempt to present <PAPasscodeViewController: 0x75d1c10> on <ServerViewController: 0x818b390> whose view is not in the window hierarchy!
actually this is confusing because I think my GeneralViewController is now the Active ViewController again...
Maybe I am just blinded by the simplicity of this Problem... but maybe someone here can help me understand.
I did NOT find any solution in any other post here in StackOverflow or other sites concerning that exact problem!
You have to remove self as observer when your ServerViewController is not shown. Add the following code to ServerViewController:
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

Open View from didReceiveRemoteNotification

I have this question asked few times and I have tried a few different methods but have not been successful.
The latest method I have tried is as followed :
I included the ViewController that I wanted to show. I then put this code in the didReceiveRemoteNotification method.
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
// [self.window.rootViewController presentViewController:pvc animated:YES completion:nil];
[(UINavigationController *)self.window.rootViewController pushViewController:pvc animated:NO];
This did not work. I think the problem I may be having is that my initial view is not a navigation controller like a lot of the examples show.
This is a picture of my story board> The VC that I want to send the user to is the car finder (bottom right)
Can someone explain to me what I might be doing wrong?
You could use basically postNotification when you receive the Remote Notification
for exmaple in your didReceiveRemoteNotification post notification like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
now in your FirstViewController's you can register the FirstViewController for this notification like this
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
and in your method
-(void)pushNotificationReceived{
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
don't forget to remove the observer from notification in your dealloc method
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I think the simplest solution would be to show the CarFinderViewController as a modal view instead of trying to push it to a navigation controller which may or may not be visible at the time.
Another important point to avoid further inconsistencies I'd recommend you instantiate your CarFinderViewController from the storyboard instead of directly through the class methods.
Something like:
UIViewController * vc = self.window.rootViewController;
// You need to set the identifier from the Interface
// Builder for the following line to work
CarFinderViewController *pvc = [vc.storyboard instantiateViewControllerWithIdentifier:#"CarFinderViewController"];
[vc presentViewController:pvc animated:YES completion:nil];

How to present a modal view controller when the app enters in foreground?

I'm trying to present a Modal View Controller when the app enters in foreground.. These are my files:
AppDelegate.m :
#import "AppDelegate.h"
#import "MainViewController.h"
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.window makeKeyAndVisible];
MainViewController * vc = [[MainViewController alloc]init];
[vc myMethodHere];
}
MainViewController.h :
//[..]
-(void) myMethodHere;
MainViewController.m :
-(void)myMethodHere{
NSLog(#"myMethodHere Activated.");
TWTweetComposeViewController *tweetViewController = [[TWTweetComposeViewController alloc] init];
[self presentModalViewController:tweetViewController animated:YES];
}
NSLog(#"myMethodHere Activated.") works.. so I can't understand why "presentModalViewController" doesn't! What should I edit/add? Maybe a delay? Thanks for your help..
p.s. I know my english sucks.. Forgive me :)
I wouldn't rely on the methods in your app delegate for this (even though it seems like the obvious solution) because it creates unnecessary coupling between your application delegate and the view controller. Instead, you can have MainViewController listen for the UIApplicationDidBecomeActive notification, and present the tweet composer view controller in response to this notification.
First, register for the notification in -viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethodHere) name:UIApplicationDidBecomeActiveNotification object:nil];
}
Now, when this notification is received when your app returns from the background, myMethodHere will be invoked.
Lastly, remember to remove yourself as an observer when the view unloads.
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

Notification not being recognised

I am trying to post a notification without much success! I can do it
ok for the keyboard without issue but now am trying a custom one as
follows:
In my rootview I have this
.h
-(void) allowEdits:(NSNotification *)notification;
.m
//this section is run in method to present the passcode entry form
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(allowEdits:) name: #"PasscodeOK" object:nil];
PasscodeEntryViewController *vc = [[PasscodeEntryViewController alloc]
init];
[self presentModalViewController: vc animated:YES];
[vc release];
// and this is the response to the notification
-(void) allowEdits:(NSNotification *)notification {
NSLog(#"notification fired");
}
// in the vc instance I have this to notify passcode was ok
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PasscodeOK" object:nil];
[self dismissView];
But the allowEdits never gets called?
Could you try posting your notification with:
[[NSNotificationCenter defaultCenter] postNotificationName:#"PasscodeOK" object:self];
As sender take the vc instance (self) instead of nil. Maybe that's solving your problem.