I am struggling with this problem for a few hours now.
I have a view with a tableView and custom cell in it. What I am trying to do is to perform a segue which is in my viewController from the custom cell. The first thing I did was to create a variable called "parent" in my cell.swift with the type "viewController".
weak var parent : ViewController!
After that, I'm just trying to perform the segue like this :
parent.performSegueWithIdentifier("eventDetails", sender: parent)
And I have the following error : Receiver (<Deevent.ViewController: 0x7fb99074f5d0>) has no segue with identifier 'eventDetails'
So I tried something else... I created a button in my ViewController and connected a segue to the next view (everything from the storyboard file)
In my viewController.swift I created the following function
func viewEventDetails() {
performSegueWithIdentifier("eventDetails", sender: self)
}
and this one in my cell.swift :
func viewEvent(sender: AnyObject) {
parent.viewEventDetails()
}
So when I call it from the cell, it crashes with the same error than before but when I click on the button it's working. I even tried to click on the button programmatically btnDetails.sendActionsForControlEvents(UIControlEvents.TouchUpInside) and I had the exact same error.
I've already tried to clean my project and delete it from the simulator. I'm really missing something here... hope somebody can help me.
Thanks !
It sounds like you need to give your segue an Identifier.
A view controller can have multiple segues, and so you need to define which one you want to use. In your case, in your code you are using the Identifier "eventDetails".
Assuming you are using a Storyboard, you need to click on the segue arrow between the two view controllers, and in the Attributes Inspector on the right, set the Identifier value to "eventDetails".
Related
Trying to perform a segue "toLogin" when the login button is pressed. Segue is named and I control-dragged the button to the block of code to make sure they are associated. Very new to coding and not sure where I went wrong.
Currently, when button is pressed it changes color but does nothing. I also previously set it to print something when pressed but that never occurs either.
Screenshot of code, storyboard
For you to connect a button to a function, the function needs to look like below
#IBAction func login(_sender: Any) {
}
You will then need to connect to the blank circle next to the function on the left.
Regarding your screenshot, each segue linked to the whole main storyboard as highlighted showing. Not linked to button. Remove those two segues from storyboard first, and linked each segue to storyboard reference or next View Controller as attached image.
Make sure you have connected your button to the #IBAction in your UIViewControllerConnect IBAction to UIButton
Looks like you are triggering segue through UIBarButtonItem,
Swift 4.2,
loginButton.action = #selector(login(sender:))
#objc func login(sender: UIBarButtonItem) {
//Perform segue
}
Thanks for answering everybody. I'm still not sure what exactly my issue was but I decided to re-create the storyboard page without using UIBarItems and it worked. I'm guessing that something about the UIBar was preventing interaction.
i'm fairly new to swift, so please bear with me.
right now my problem can be broken down to this:
I have one Test View Controller that can display my 'Test' object by showing the description and the title. I also have an array of Test objects. In the top right hand corner, there is a 'skip this test' button, and if the user clicks on it, the viewcontroller will segue to itself, but change the Test object that is being displayed, e.g. its just basically looping through an array of Tests. I have changed the prepare for segue methods accordingly to push the data through the view controllers.
However, I want to be able to move to a completely different ViewController (lets just call it FinalViewController) if I have reached the last Test in my Test array.
Now this is the part that I can't fix.
I would like to create a segue directly from the 'skip test' button, only that it segues to a different view controller, depending on a certain condition. However, as i tried creating a segue in IB by right clicking on the Button and pulling it to the FinalViewController, it erased my previous segue I had for that button.
Does anybody know if there is a fix for this problem? thank you!!!!
However, as i tried creating a segue in IB by right clicking on the
Button and pulling it to the FinalViewController, it erased my
previous segue I had for that button
Actually, you don't want to do that, instead, you should drag from the controller itself, not from the button because if your segue has been created based on a button, tapping on it should always perform it and this is NOT what you want.
After creating a segue from the ViewController, you can -programmatically- call performSegue method and handle what data should be passed to the next viewController by implementing prepareForSegue method.
For more information, check my answer to know how to create multiple segues with identifiers and work with them.
EDIT:
If you want to push to the same current ViewController, performSegue method would not be the optimal solution. You should instead push/present to same ViewController it self:
class ViewController: UIViewController {
var myString: String?
override func viewDidLoad() {
super.viewDidLoad()
// here we go
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sameViewController = storyboard.instantiateViewControllerWithIdentifier("ViewControllerStoryboardID") as! ViewController
sameViewController.myString = "the value of the new myString"
navigationController?.pushViewController(sameViewController, animated: true)
print(myString)
}
}
Probably, you don't want to implement it in viewDidLoad, it's just for demonstration purpose.
Make sure that the ViewController has a storyboard ID (in code snippet, I assume it is "ViewControllerStoryboardID"):
My app's navigation flow looks a bit like this:
UINavigationController - MasterViewController > DetailViewController > InfoViewController
MasterViewController contains the following method:
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
In DetailViewController, there is a similar method:
#IBAction func unwindToDetail(with segue: UIStoryboardSegue) {}
I use these methods, along with UIButtons, to allow the user to advance forward and back through the navigation hierarchy. In interface builder, I see the method under DetailViewController when I right click on "Exit" in InfoViewController, but when I right click on "Exit" in DetailViewController, no other unwind segues are listed.
I have consulted multiple online sources (Ray Wenderlich, relevant StackOverflow questions) instructing the correct way to produce unwind segues in interface builder, but none of these have helped solve the issue. Right now, I need help figuring out what the problem is in the first place. As development usually goes, it's probably something staring me square in the face.
I am running Xcode 8.1 using Swift 3. Thank you.
To re-iterate: not only an Action for a Storyboard Unwind Segue has to be placed in the same source file as class definition for an unwind-to (destination) View Controller (e.g., #IBAction func prepareForUnwind(segue: UIStoryboardSegue), detected as prepareForUnwind[With]Segue in a "Presenting Segues" list), but also that View Controller cannot have ANY extensions in ANY secondary source files. You have to merge class definition and all extensions into a single source file.
(As of Xcode 8.2.1.)
In my case, I had a complicated inheritance in my view controller and it was a reason why Interface Builder did not see my unwind. So this workaround works for me well:
Go to YouCollViewController.swift file and delete all classes, protocols, generics, etc. your view controller implements in view controller's declaration
Inherit your view controller from UIViewController
Go to the storyboard and connect your action with the unwind, it should appear in unwinds list
Go back to YouCollViewController.swift file and discard all the changes
I consulted Apple's Developer Library (specifically the page "Using Unwind Segues"). There, the example definition of an unwind action is:
#IBAction func unwindToMainMenu(sender: UIStoryboardSegue) {
let sourceViewController = sender.sourceViewController
// Pull any data from the view controller which initiated the unwind segue.
}
Applying this example in my code, I changed my unwind action declarations to:
#IBAction func unwindToMaster(sender: UIStoryboardSegue) {
print("Unwinded to master.")
}
and
#IBAction func unwindToDetail(sender: UIStoryboardSegue) {
print("Unwinded to detail.")
}
I also made sure that each method was contained within the same file as MasterViewController's class declaration. After further testing, I found that all extensions of MasterViewController had to exist in the same file for interface builder to find and recognize the unwind segue.
Now, in storyboard, the exit menu shows both unwind segues. My conclusion is that by fiddling around with where the methods are placed and how they are declared, a configuration that interface builder can recognize will be found. I hope it will be less touchy in the future, as my current method organization is very long and difficult to navigate.
Because none of these answers helped me and I didn't want to mess around with my code that much. Here another solution you can give a try.
Starting from the point where you have already added the unwind function to your MasterViewController.
First I have gone ahead and added a new ViewController to my storyboard as well as a new Cocoa Touch Class File of type UIViewController and connected it with my Storyboard one (I called it the HelperViewController).
Then you can add the same unwind function, you already have inside your MasterVC to your newly created HelperVC.
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
Now connect the Helper to your DetailVC. Your Storyboard should look somewhat like mine. You should get the same option as me if you ctrl + drag and drop to the exit of your DetailVC. When the connection has been established and you hover over the newly created segue both the Master and the HelperVC should be highlighted. Now you can delete the HelperVC again and everything should work as expected.
I hope that helped!
With swift 4 XCode 9.2 I found that you need to drag the reference from the yellow icon at the top of the viewController to the "Exit" reference of the target viewController in the left details panel. Hope this helps!
Sometimes XCode restart makes the actions appear.
I've much the same problem as in this question but these solutions don't work. Currently running xcode 7.3.1.
I've a split view controller app, that modally presents a save record view controller. On the save VC, there are a save and cancel button that should (in both cases) unwind back to the master view.
Within the Master View Controller, I have the following code:
#IBAction func unwindToSegue (segue: UIStoryboardSegue) { }
BUT, there's a compiler error: Only instance methods can be declared #IBAction. There is the suggestion to delete #IBAction, but while this removes the error I can't connect to this action in the child VC.
With or without #IBAction in the unwind method, I get the same issue described in the referenced problem - dragging a line from my UIButton to the Exit button in Storyboard IB, does not show any action to connect with.
You need to put the function inside the UIViewController.
class MasterViewController: UIViewController {
#IBAction func unwindToSegue(segue: UIStoryboardSegue) { }
}
I got this error simply when I had an extra parenthesis in my code... it was positioned before the IBAction method, so it essentially cut it off from being inside the UIViewController class, as Tomas suggests. So, check that all of your parenthesis are in place.
#IBAction is very picky with regard to syntax including white spaces between the string. for an example, nameA.txt ="" is not acceptable.
you need to have equal white space contiguous to string such as
nameA.text = ""
I'm struggling to change to a UI View Controller as a game over screen, on this screen I plan on showing the score, reset and advert. I'll show you my code that I have already then below I'll list how my project is set up.
The game runs however once contact is detected the crash states
Thread 1 EXC_BAD_INSTRUCTION (code=EXC1386_INVOP,subcode=0x0)
Here is the code I've used so far...
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var viewController: GameViewController!
var secondViewController: GameOverViewController!
override func didMoveToView(view: SKView) {
//lots of code here
func didBeginContact(contact: SKPhysicsContact) {
if( moving.speed > 0 ) {
moving.speed = 0;
self.viewController.performSegueWithIdentifier("GameOverViewController", sender: self)
}
I currently have the below set up:
My two view controller files GameViewController.swift & GameOverViewController.swift
In addition to my current GameViewController view I have a new view controller on my storyboard with the following attributes.... Class:GameOverViewController & Storyboard ID:GameOVerViewController
A triggered segue is set up (push) from GameViewController to GameOverViewController
A then have the following code in my GameScene.Swift file
If anyone could help me that would be great.
Thank you.
performSegue:withIdentifier: should work unless you have not setup the the storyboard correctly.
What error do you get on doing performSegue:withIdentifier: ?
Did you setup a segue in storyboard connecting the two view controllers and does that segue have an identifier called secondViewcontroller?
Take a look at this Storyboard tutorial.
Maybe you are trying to push a view controller without a navigation stack, if that's your case, try presenting modally your view controller, check as well how do you have wired the segue. Sorry for my bad english.
Change your performSegue call to
self.viewController.performSegueWithIdentifier("DOES_NOT_EXIST", sender: self)
And re-test. Do you get the same error? If so, you haven't named your segue properly. The segue name set in the Interface Builder must exactly match the segue name you try to call in your code. To fix this: Select the segue in the interface builder, Read the Identifier box to the correct name, update your performSegue call to use exactly that string and rebuild. (if you update the identifier in the Interface builder, make sure you clean the project before rebuilding to ensure the new symbol is picked up).
If, however, the test results in a different error, "'Receiver <> has no segue with identifier 'DOES_NOT_EXIST'" then your original perform segue call was working fine. Put it back the way it was. Something else is causing your crash.