How to perform segue from within a SKScene? - iphone

I have been trying to perform a segue from within a sprite kit SKScene layer. My application requires the user to touch an image on the scene that would push up a new UIViewController. But every time I try to perform from within the SKScene game layer, it gives me output with has no segue with identifier error. I do have a segue and have specified it with an identifier.
My simple question, how can one perfrom segue with a SKScene game layer running? Please help me out.

Segues belong to view controllers, not SpriteKit scenes. If you want to perform a segue from within a SpriteKit node's event handling code, you'll need to look up the view controller that owns the view presenting the scene. For example, in a SKScene subclass' touchesBegan:withEvent: method:
UIViewController *vc = self.view.window.rootViewController;
[vc performSegueWithIdentifier:#"id" sender:nil];

Swift version :
self.view!.window!.rootViewController!.performSegueWithIdentifier("gameOverSegue", sender: self)

Related

Basic Transitioning Between View Controllers in Swift

I am working to implement code that will move between 2 View Controllers, vc1 and vc2.
vc1 toggles between 2 SKViews, and vc2 just displays some simple things in UIView.
vc1 and vc2 are both in the main storyboard.
vc1 is displayed first, then at a point in an SKScene it segues to vc2:
let currentViewController: UIViewController = (self.view?.window?.rootViewController)!
currentViewController.performSegue(withIdentifier: "VC1toVC2", sender: currentViewController)
After a short delay in vc2, it segues back to vc1:
self.performSegue(withIdentifier: "VC2toVC1", sender: self)
These segues work.
Then, with the same code as above (using the same segue):
let currentViewController: UIViewController = (self.view?.window?.rootViewController)!
currentViewController.performSegue(withIdentifier: "VC1toVC2", sender: currentViewController)
...the 2nd time it does not work to segue from vc1 to vc2. There's no exception, just that vc2 does not display.
I found some other posts that don't address the issue, for example:
* Swift segue not working? - suggests that UI updating has to be in main thread, and this one that shows how to do that in Swift 3 - How do I dispatch_sync, dispatch_async, dispatch_after, etc in Swift 3? --- I get the same result
* other posts suggested using the view controller's .show or .present method --- I get the same result
Any thoughts/guidance?
I solved this using a delegate as other posts have mentioned, eg How to call method from ViewController in GameScene. The delegate allows the SKScene object to call / run code in its View Controller. This allows the View Controller to perform the segue instead of trying to perform the segue from the SKScene object (not sure that's even possible, to perform the segue from the SKScene object). Here's a simple tutorial as well https://useyourloaf.com/blog/quick-guide-to-swift-delegates/ if you're not all that familiar with delegates in Swift. I can post more details if it would help anyone.

Background view controller responding to touch events?

I have a main view controller which overrides
touchesBegan and plays a sound when hitting a certain screen position. I have a show segue from this view controller to another one, my custom settings view controller. However, when I slide my finger across this new one, the background view controller is still responding to my touches, as a sound is still being played.
I do not have a navigation controller implemented, and it seems like other segue types have this same issue with the touch events responding in the background. Shouldn't the first view controller not be responding to these touches after the segue? Or if I am misunderstanding, what is the proper way to stop touch events being called in the background VC?
Edit: in first view controller, when printing view.isUserInteractionEnabled, I get true despite the view controller being in the background. Not sure if this is relevant.
Edit 2: I tried adding a line in prepare for segue override self.view.isUserInteractionEnabled=false, but weirdly enough, only does this disable touch when dismissing the settings view controller.
Even more strange: if I override touchesBegan in my new view controller, it silences both the touchesMoved and touchesBegan methods in my original view controller. But if I just override touchesMoved in my new controller, the touchesMoved method in both view controllers are called.
I read that we need to override all 4 of the touch handlers and call the superclass method, which I forgot to do. But overriding all 4 methods in both these classes still cause this underlying touch event to go through.
I also would like to stick to this approach rather than a gesture recognizer. I'm assuming there has to be a proper way to handle what looks like this responder chain?
Here's a simple way to replicate: If you create a simple project with two view controllers, A and B, and have a button cause segue from A to B, and implement the touches method in VC A (and let's say print something to the console), then even after segue, the exact same thing happens. VC A is still handling touch events.
If you want to prevent touches on the previous view try presenting the next view to fullscreen.
let controller = segue.destination as! YourViewController
controller.modalPresentationStyle = .fullScreen

Load custom UIView with Nib in ViewController

I'm making RadioPlayer with model, view and controller. Model would be a shared instance and all initialization (play, pause etc.), view is just button and slider and controller should merge view and model...
Now I've got problem how to do this especially if using nibs... Here is good example with programatically written uiview (using loadView in ViewController) .- Objective-C, Need help creating an AVAudioPlayer singleton (Wolfgangs solution) but I would like to do it with nib.
So in short - Create nib for UIView, add that view to its controller (with its model). So this would be only controller for that view (slider + play/pause) not whole view (iPhone screen).
Thanks.

Open a UIImagePicker from a UIImageView

I am writing a simple app where I have a UIImageView that when clicked on, should open a UIImagePickerController, and once an image is selected, is should just assign that image to the UIImageView
I started by sub-classing UIImageView, and giving it a touchesBegan which would open an ImagePicker.
My question is, since only a UIViewController can call presentModalViewController to show the imagePicker, how should I go about this?
It's bad design to have your a view reference it's controller (though I guess my imageview is a subview). So I don't know how I'd pass the message up to the controller.
The other option is to detect touches in the controller to begin with, but then the only way I can see to tell if the touch was on the imageview is to actually test if the touch is within the frame of the imageview. This approach seems clunky to me... Am I missing something obvious?
Any thoughts on which method to go with, or any suggestions on a better method would be much appreciated! Thanks!
You don't necessarily need to subclass UIImageView to do this. You can have it as a subview of your main UIView for some UIViewController, and add a UIGestureRecognizer to the UIImageView. Then the method that tapping or swiping the UIImageView triggers will be in your UIViewController, so you can easily present a modal view from there.
When you init the UIImageView subclass, pass a reference to the view controller that loads the image view.
Then, your touchup inside on the UIImageView can call presentModalViewController with that view controller.
The Objective C way of doing this is to declare a custom delegate that your view controller implements. So for your case, it would a have a single method, something like viewTapped. Have your custom class call this delegate method whenever it is clicked.
Then make your view controller implement this delegate and launch the modal view controller when the delegate method is called.

How to controll second UIView (subview) from a different UIViewController file in one XIB

I am strugling on the following task.
I am trying to control my subview from another viewController class.
What I did and does not work is this.
I inserted an object and changed it class to my second viewController class.
Then I connected its UIButton outlet to a button I have on my subview.
I then connected the buttons action to the outlet of my second view controller.
What I get when I run is this.
It all shows up well but when I try to touch the button that resides in my subview app crashes. I am only left with a worringing: "Action unavailable: The "Touch Up Inside" event of "Rounded Rect Button".
It's probably my logic that is incorrect. Thanks for help.
Well after a long research I got an answer to my problem.
As it appears I was doing everything right.
The problem is that after the initial XIB file is initialized it autoreleases all views and subviews. So to prevent from gettig your second view controller from being released implement this method
- (void)awakeFromNib {
[self retain];
}
in your view controller .m file.
This method will retain your second view controller alive and allow it to recive and respond to UI actions.