Swift performSegueWithIdentifier not working
[Assuming that your code is not crashing, but rather just failing to segue]
At least one problem is:
self.performSegueWithIdentifier("Test", sender: self)
should be:
dispatch_async(dispatch_get_main_queue()) {
[unowned self] in
self.performSegueWithIdentifier("Test", sender: self)
}
Remember that all UI operations must be performed on the main thread's queue. You can prove to yourself you're on the wrong thread by checking:
NSThread.isMainThread() // is going to be false in the PF completion handler
ADDENDUM
If there's any chance self
might become nil, such as getting dismissed or otherwise deallocated because it's not needed, you should capture self weakly as [weak self]
not unowned
, and use safe unwrapping: if let s = self { s.doStuff() }
or optional chaining: self?.doStuff(...)
ADDENDUM 2
This seems to be a popular answer so it's important to mention this newer alternative here:
NSOperationQueue.mainQueue().addOperationWithBlock {
[weak self] in
self?.performSegueWithIdentifier("Test", sender: self)
}
Note, from https://www.raywenderlich.com/76341/use-nsoperation-nsoperationqueue-swift:
NSOperation vs. Grand Central Dispatch (GCD)
GCD [dispatch_* calls] is a lightweight way to represent units of work that are going to be executed concurrently.
NSOperation adds a little extra overhead compared to GCD, but you can add dependency among various operations and re-use, cancel or suspend them.
ADDENDUM 3
Apple hides the single-threaded rule here:
NOTE
For the most part, use UIKit classes only from your app’s main thread.
This is particularly true for classes derived from UIResponder or that
involve manipulating your app’s user interface in any way.
SWIFT 4
DispatchQueue.main.async(){
self.performSegue(withIdentifier: "Test", sender: self)
}
Reference:
https://developer.apple.com/documentation/uikit
performSegueWithIdentifier not working if called from viewDidLoad
EXPLANATION:
Your View hasn't appeared yet when you call your checkStoredUser()
.
EASY FIX:
Put it in viewDidAppear()
like this:
override func viewDidAppear(animated:Bool) {
super.viewDidAppear(false)
checkStoredUser()
}
swift performSegueWithIdentifier sender value
As @iosDev82 says in his answer, sender is an optional that names the object (if any) that triggered the segue.
If you trigger a segue through code in a view controller, you could pass the view controller (self), or you could pass nil. It's just a piece of information that is passed along to prepareForSegue (again as iOSDv82 says.)
If you trigger a segue in the code of an IBAction method, your IBAction may have it's own sender parameter (frequently a button.) In that case you can pass along the sender parameter to the performSegueWithIdentifier
method.
Example:
@IBAction func buttonAction(sender: UIButton)
{
//In this case the button IBAction takes a pointer to the button as a param.
//Pass it on to the segue in case performWithSegue needs it.
self.performSegueWithIdentifier("someID", sender: sender)
}
prepareForSegue and PerformSegueWithIdentifier sender
There are, effectively, two ways you can trigger a segue. The first is via an action on a UI element in Interface Builder, the second is using performSegueWithIdentifier:sender:
in your code. I say 'effectively', because under the covers, when the scene is loaded from the storyboard, an action handler is configured that ultimately calls performSegueWithIdentifier:sender:
When performSegueWithIdentifier:sender:
is called, the segue object is delivered to your view controller's prepareForSegue:sender:
function.
In the case where the segue was initiated by an action on a UI element then the sender will be that UI element (i.e. if it is an action connection on a UIButton
then the sender
will be the UIButton
instance).
If the segue is initiated by your code calling performSegueWithIdentifier:sender:
then the sender
will be whatever object you passed as the sender
. This could be your view controller, a button, an array, anything. So yes, if you pass "Hello World" to performSegueWithIdentifier:sender:
as the sender
value then this will be the sender
in prepareForSegue:sender:
In terms of the order of operations:
performSegueWithIdentifier:sender
is called, either by your code or as a result of an action on a UI element- If your view controller implements
shouldPerformSegueWithIdentifier:sender:
then this function is called. If this function returnsfalse
then the segue is cancelled - The segue object and destination view controller object are created
- If your view controller implements
prepareForSegue:sender:
then this function is called. - Once
prepareForSegue:sender:
returns, the segue completes.
Swift: performSegueWithIdentifier during unwind not working
In VC1 you need a function:
@IBAction func unwindToVC1(segue:UIStoryboardSegue) {
}
Then in your storyboard ctrl drag from the yellow view controller icon to the Exit icon and select unwindToVC1:
from the pop up
Give the unwind segue an identifier, say unwindToVC1
Now, in VC2, create your button touchUpInside
handler:
func buttonTapped(sender:UIButton) {
self.performSegueWithIdentifier("unwindToVC1")
}
when you set up your button programatically, add this method as the action handler:
button.addTarget(self, action: "buttonTapped:", forControlEvents: .TouchUpInside)
How to call performSegueWithIdentifier from xib?
The problem is that your UIView
subclass is calling viewController().goToSecond()
. That's not doing what you think it is. The viewController()
isn't referencing the view controller that loaded your custom view. It's instantiating a second, orphaned instance of that class (not connected to any storyboard) and therefore cannot find the segue.
If you're really going to have this custom UIView
subclass initiate a segue, you need to pass a reference to your original view controller to the custom view. So add a property to the custom view subclass that can hold the reference to its view controller, and when the view controller instantiates this custom view, it has to set that property.
For example:
import UIKit
protocol CustomViewDelegate: class { // make this class protocol so you can create `weak` reference
func goToNextScene()
}
class CustomView: UIView {
weak var delegate: CustomViewDelegate? // make this `weak` to avoid strong reference cycle b/w view controller and its views
@IBAction func toSecondButton(sender: AnyObject) {
delegate?.goToNextScene()
}
}
And then
import UIKit
class ViewController: UIViewController, CustomViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let myCustomView = NSBundle.mainBundle().loadNibNamed("customView", owner: self, options: nil)[0] as! CustomView
myCustomView.delegate = self
// ... do whatever else you want with this custom view, adding it to your view hierarchy
}
func goToNextScene() {
performSegueWithIdentifier("toSecond", sender: self)
}
...
}
Swift performSegueWithIdentifier shows black screen
I've build your app and everything works, maybe you've missed something, here is my solution (Note: Code is in Swift 3.0, but should be easy to adopt it to Swift 2.*):
The storyboard:
Set the segueToTraits identifier:
Set the TraitViewController class as custom class in the storyboard:
The view controller with the buttons:
import UIKit
class ViewController: UIViewController {
let boyGender = "boy"
let girlGender = "girl"
var selectedGender: String?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToTraits"{
if let gender = self.selectedGender {
let traitVC = segue.destination as? TraitViewController
traitVC!.gender = gender
}
}
}
func sendGenderToTraitsView(gender : String?){
performSegue(withIdentifier: "segueToTraits", sender: self)
}
@IBAction func button1(sender: UIButton) {
selectedGender = boyGender
self.sendGenderToTraitsView(gender: selectedGender)
}
@IBAction func button2(sender: UIButton) {
selectedGender = girlGender
self.sendGenderToTraitsView(gender: selectedGender)
}
}
The trait view controller:
import UIKit
class TraitViewController: UIViewController {
var gender: String = ""
override func viewDidLoad() {
super.viewDidLoad()
print("gender: \(gender)")
}
}
Result:
You can find the sample project here
performSegueWithIdentifier is being skipped *SWIFT
You should move your code into the viewWillAppear
or viewDidAppear
method.
Then it should use properly.
But now the view flickers a short time. To remove that flickering, just hide the view in your viewWillApear
method:
self.view.hidden = true
Also the viewDidLoad
method doesn't get called everytime the view appears but only the first time it loads. If you for example perform a segue and return back to the view, it doesn't load again but only calls viewWillAppear
and viewDidAppear
again.
performSegueWithIdentifier Not Working - Swift
That's because you can't push view controller without UINavigationController. Please put UINavigationController or please set segue Kind "Modal" not "Push"
Related Topics
Conflicting Definition of Swift Struct and Array
Enable + Disable Auto-Layout Constraints
Function Taking a Variable Number of Arguments
Wcsession Has Not Been Activated
Swift, Pass Data Back from Popover to View Controller
Variable P Passed by Reference Before Being Initialized
Swift: Overriding Didset Results in a Recursion
How to Get Motion Events with the Apple Tv Remote
Format Float Value with 2 Decimal Places
Scenekit -- How to Get Animations for a .Dae Model
Seeking an "Exit" Equivalent in Swift
Swift - Lazy Var VS. Let When Creating Views Programmatically (Saving Memory)
One-Way Platform Collisions in Sprite Kit
Swift: Dictionary Access via Index
How to Automatically Reflect Coredata+Icloud Changes in Swiftui View
Creating a Future Date in Swift with Nsdate()
How to Fix ' *Pod* Does Not Support Provisioning Profiles' in Azure Devops Build Agent