Swift segue performed multiple times - swift

A segue in my app is being called multiple times, which is causing the view to continuously "load" until the app stops calling the segue function. It does this about 4 times until it's finished. After placing breakpoints in the code I noticed that the app is bouncing between these two functions:
if success {
self.performSegueWithIdentifier("startGame", sender: "user")
}
That is the action that triggers the segue (the user swipes something). It then goes to the next breakpoint:
if (segue.identifier == "startGame") {
let destinationNavigationController = segue.destinationViewController as! GameViewController
destinationNavigationController.user = self.users[self.currentUser]
}
The app goes back and forth between the two sections about 4 times. When I created the segue in my storyboard I made sure to wire the segue from the view controller itself (not a table/UI view) to the destination view.
What else can I do to fix this?
Thanks!

In storyboard, create a segue by holding control and dragging from the yellow icon of the 1st view controller to the 2nd view controller.
Give it an id, and the kind should be push if they are embedded in a navigation controller.
In your 1st view controller class:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "startGame" {
let viewController = segue.destinationViewController as! GameViewController
// this next view controller should have property that will store passed value
viewController.user = self.users[self.currentUser]
}
}
When you want to move to the next view controller:
performSegueWithIdentifier("startGame", sender: self)

Related

How to pass data between two screens while both are elements in NavigationController in Swift?

I have a set of storyboards under the UINavigation Controller. One of these screens contains a table view and I need to send the data of the clicked row to the next screen. I am aware that doing so would require me to use segue. But then how do I get the Navigation Bar and the Navigation Button
For better understanding I have uploaded the screen shot of my first screen. Clicking on the detail button is going to send the challenge object to next screen. However, I am looking forward to having the same navigation bar on the top of the next scree. Any idea how can I accomplish such objective?
Currently if I press on details button, I'll get the details of that challenge in the terminal.
#IBAction func CAStartChallenge(_ sender: UIButton) {
let tag = NSNumber(value: sender.tag) as! Int
print("challenge name to be printed : \(challengeTableConent[tag].display()) ")
}
In your storyboard you want to drag a segue between the view controllers, like so:
Storyboard segue dragging
Use either Show or Push (deprecated) options for the segue. Give this segue an appropriate identifier, such as Details.
Then in your button function you can add these:
#IBAction func CAStartChallenge(_ sender: UIButton) {
let tag = NSNumber(value: sender.tag) as! Int
performSegue(withIdentifier: "Details", sender: challengeTableConent[tag])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Details",
let destination = segue.destination as? DestinationViewController,
let model = sender as? ChallengeTableContentType {
// pass through model to destination view controller
destination.model = model
}
}
You can then configure the destination view controller using its specific model when it appears.
First of all
Passing data through screens using segues is simple. Just check this answer
Pass data through segue
It will explain exactly how to do it
Second
Check the bug on your button I think you mean "Details"
Third
Check the type of segue, you might not used push or show detail. Also select the details view and make sure that "Simulated Metrics -> Topbar" is set to inferred
Some prints to help
This will ensure that the navigation bar comes from the previous controller
This is how your segue should look, do not forget to give an identifier to your segue

iOS QR code scanner triggering actions multiple times

I am using the QR code reader code from AppCoda (http://www.appcoda.com/qr-code-reader-swift/#comments) and converted it to Swift 3. The base code works perfectly fine.
However, what I want to achieve is to retrieve a String from the QR reader, store it in a variable, and pass the variable to a following view controller. So I added a bit of code to it to get the following:
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
if metadataObjects == nil || metadataObjects.count == 0 {
qrCodeFrameView?.frame = CGRect.zero
messageLabel.text = "No barcode/QR code is detected"
return
}
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if supportedBarCodes.contains(metadataObj.type) {
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
qrCodeFrameView?.frame = barCodeObject!.bounds
if metadataObj.stringValue != nil {
messageLabel.text = metadataObj.stringValue
}
//
//
// CODE I ADDED STARTS BELOW
//
performSegue(withIdentifier: "showMenu", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showMenu"{
let tabVc = segue.destination as! UITabBarController
let navVc = tabVc.viewControllers?.first as! UINavigationController
let menuVc = navVc.viewControllers.first as! MenuViewController
menuVc.qrScan = self.messageLabel.text
}
It actually achieves what I wanted it to do, but it somehow triggers the "performSegue" multiple times. The transition animation of the first segue goes halfway, and then the second one happens.
The segue "showMenu" is a manual segue connected from the view controller of the QR Reader view to a tab bar controller that houses a navigation controller and Menu view controller.
Things I've tried:
Print the passed on variable in the viewdidload function of Menu view controller. The string gets printed out twice.
Added a hidden button on the QR reader view and change the segue connection of "showMenu" from the view controller to the button. Removed perform segue from code. While holding the camera in place to scan qr codes, pressing the button performs the intended function and the segue is only triggered once.
With the same setting as (2), I programmatically trigger the button by using a touch up inside event when a qr code is scanned. The segue gets triggered twice.
Added breakpoints for performSegue and the if clause right above it. After I scan something, and press the "continue program execution" button, the program loops between the two breakpoints on and on.
If anyone can enlighten me a bit over here, I would be very grateful. Thanks a bunch for the help in advance.
The issue was fixed by adding the following line of code after the segue was performed:
self.captureSession?.stopRunning()
However, the question of why doesn't unwind segue have a similar issue still remains.
I've just solved the same problem. You have to create an unwind to the previous view.
To do this in the interface builder, you have to ctrl-drag from the controller to the exit in the controller you're actually in (not the one you want to unwind).
Once you have done this, you have to set an identifier to this unwind segue (in your case "showMenu". To do this, you have to the unwind segue from the scenes menu on the left part and set the identifier name on the Attributes inspector.

Data between view controllers not passing

I am creating an application in which there are 6 view controller in storyboard. The thing is that data is shared between the default view controller and the first one ( say A and B) which i added. i am using the prepareforseque method for passing data. the problem started when i added two more view controller. lets say C and D i created two new swift files and changed the two view controller class name. i created a textbox and button in C and label in D. when i pressed the button, the value of the text field is not passing into the D view controller although i used the same methods and code which i used for A and B. do i have to do anything else when i want to pass data between two newly added view controller.
first viewcontroller in which when a button is pressed value 1 needed to be passed:
class PlaySelectMenu: UIViewController {
var value = Int()
#IBAction func twotofive(sender: AnyObject) {
value = 1
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextView : PlayGameView = segue.destinationViewController as! PlayGameView
nextView.x = value
}
}
the second view controller which receive the value and print it
import Foundation
import UIKit
class PlayGameView: UIViewController{
var x = Int()
override func viewDidLoad() {
super.viewDidLoad()
print(x)
}
}
here i have added both the view controller from the object library and not working with the default one which is present in storyboard by default. i dont know why these two viewcontroller are not working. please help.
Regards Dev
One solution would be to write the data out to NSUserDefaults and then read it back from NSUserDefaults in the other view controller. Probably not the proper or correct way to share data between two view controllers, but it's been a reliable work around for me.
Other than that, you'd need to share your code so that we can see what's occurring.
Can you post also the code in your controllers C & D. And also if you have copy/paste the code inside your first two controllers into the two others, are you sure that in your prepareForSegue method you have changed the name of the destination segue ?
Assuming you have created the segue in Storyboard:
All you need is to do is put all of needed updates in prepareForSegue because twotofive is called after prepareForSegue.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
value = 1
let nextView : PlayGameView = segue.destinationViewController as! PlayGameView
nextView.x = value
}
Since you have connected your segue from button click to view controller, when you press button segue is automatically called. Instead of connecting segue from button to VC, connect VC to VC. Then in button click method at the last add below line:
#IBAction func twotofive(sender: AnyObject) {
value = 1
self.performSegueWithIdentifier("<Name of the segue identifier>", sender: self)
}
This will call your prepareForSegue. If you are calling more then one VC using segue from a VC then you can use segue.identifier to check which VC was called as below
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "CVC" {
}

How can I use the selected data from a UIDatePicker in another view in IOS8?

I'm very new to IOS 8 and programming in general. I would like to populate a UIButton's label text with the value from a UIDatePicker. When the user presses the button, a popover appears with a date picker. I have created a new view controller imbedded in a navigation controller for my date picker. They are connected using a popover segue. My question is once the user selects a date, how can I transmit this information back to the original view controller to show the value on the button label. Any help would be greatly appreciated.
To pass a value between 2 viewcontrollers using segues is easies done like this:
class VC1:UIViewController {
#IBAction func next() {
let valueToPass = NSDate() // Could be anything that conforms to AnyObject
self.performSegueWithIdentifier("segueID", sender: valueToPass) // Use this method unless you're connecting a button to a viewcontroller in storyboard
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let vc2 = segue.destinationViewController as VC2 // The viewcontroller you're going to
vc2.date = sender as NSDate // If you connected button to vc in storyboard sender will be nil, so in that case just set the vc2.date directly here
}
}
class VC2:UIViewController {
var date:NSDate! // Property you want to pass to
}

How To Dismiss Popover From Destination View Controller in Swift

I have a main view controller that has been setup in Interface Builder to open a table view controller via popover segue connected to a button. I want to be able to dismiss the popover when an item inside of my popover table view is selected in didSelectRowAtIndexPath. In Objective-c I can just typecast the the segue in the prepareForSegue delegate to a UIStoryboardPopoverSegueand pass along its UIPopoverController to the table view controller. However, in Swift my downcast fails because it sees the segue as type UIStorybaordPopoverPresentationSegue (when stepping through with the debugger) which doesn't appear to be a public API.
Here's my code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "ShowCollectionsSegue" {
if let collController:CollectionsTableViewController! = segue.destinationViewController as? CollectionsTableViewController {
if let popoverSegue = segue as? UIStoryboardPopoverSegue { // <-- This fails
collController.popover = popoverSegue.popoverController
}
}
}
}
How do I coerce the segue to a UIStoryboardPopoverSegue in order to access its popoverController property?
I'm open to solving the problem of dismissing the popover in response to a table view cell tap a different way, but it seems that when using a segue from the storyboard, the only way to dismiss the popover is by holding onto a reference to the popover controller somehow and the only way to do that as far as I can tell is to cast the segue to a popover segue which Swift doesn't want to let me do. Any ideas?
A strange problem, indeed. I noticed in the documentation, that UIStoryboardPopoverSegue does not inherit from any class. That explains why the cast does not work - UIStoryboardSegue is not its superclass. So I just tried to create a new object - it looks weird but works:
let popoverSegue = UIStoryboardPopoverSegue(
identifier: segue.identifier,
source: self,
destination: segue.destinationViewController as UIViewController)
println("Is there a controller? \(popoverSegue.popoverController.description)")
// YES !!
EDIT
But this controller will not dismiss the popover :(
The fix is to specify the segue in Interface Builder as "Deprecated Segues : Popover". Then the code would be as expected
let popoverSegue = segue as UIStoryboardPopoverSegue
if let destination = segue.destinationViewController as? TableViewController {
destination.delegate = self
self.popoverController = popoverSegue.popoverController
}