Unable to get buttons currentTitle from UIStoryBoardSegue - swift

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Choose Theme" {
if let themeName = (sender as? UIButton)?.currentTitle {
if let theme = themes[themeName] {
if let cvc = segue.destination as? ConcentrationViewController {
cvc.theme = theme
}
} else {
print("something went wrong")
}
} else {
print("couldnt get current title")
}
}
}
There is the code. I'm trying to get senders current title. I tried debugging and it prints "couldn't get current title", the value that I'm getting is nil.
What am I doing wrong?
Thanks in advance

Instead of using currentTitle, you might want to try titleLabel?.text. It seems to be more reliable. I got your program to work (tested in Xcode) using this change.

Related

performSegueWithIdentifier not working if called from viewDidLoad

I have a simple app with a loading screen. Here I check for some user details in NSUserDefaults and jump to either the login or the sign up screen.
The viewDidLoad() for the loading screen looks like this:
override func viewDidLoad()
{
super.viewDidLoad()
loadingVM = LoadingVM() as LoadingVM
print("LoadingVC")
checkStoredUser()
}
Here is the checkStoredUser()
func checkStoredUser()
{
storedUserStatus = loadingVM.returnStoredUserStatus()
if(storedUserStatus == true)
{
performSegueWithIdentifier("loadingToLoginVC", sender: self)
}
else
{
performSegueWithIdentifier("loadingToSignUpVC", sender: self)
}
}
As you can see, I decide where to go from here based on what the loadingVM.returnStoredUserStatus() returns. I am sure this returns what it's supposed to return but nothing happens.
Here is the prepareForSegue()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
print("prepareForSegue")
if(segue.identifier == "loadingToSignUpVC")
{
let signUpViewCotroller = (segue.destinationViewController as! LocalSignUpVC)
}
else if(segue.identifier == "loadingToLoginVC")
{
print("loadingToLoginVC")
let loginViewCotroller = (segue.destinationViewController as! LoginVC)
}
}
I did some digging and found a weird suggestion that seems to be working but It's not very practical not to mention right to do it like this:
func checkStoredUser()
{
storedUserStatus = loadingVM.returnStoredUserStatus()
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.0 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue())
{
if(self.storedUserStatus == false)
{
self.performSegueWithIdentifier("loadingToSignUpVC", sender: self)
}
else
{
self.performSegueWithIdentifier("loadingToLoginVC", sender: self)
}
}
}
Can anyone explain to me what's going on here, why doesn't this work and how to make it work properly? It's the first time I encounter this and I can't seem to be able to find any info on this.
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()
}

how to pass Intergers between view controllers in swift

This is my code and it's not working. LightOrDark and LightDark are Integers and should be equal when the app changes views.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "LightSegue") {
if let MinigameView = segue.destinationViewController as? MinigameView {
self.LightOrDark = MinigameView.LightDark
}
}
}
self.LightOrDark = MinigameView.LightDark this statement sets MinigameView.LightDark to current class's LightOrDark.
You need to set LightDark of MinigameView so your code should be like,
MinigameView.LightDark = self.LightOrDark
And you should follow naming standard. variable or instance name should be start with lower case not upper case.
so your instance name should be lightOrDark and minigameView instead of LightOrDark and MinigameView.
Hope this will help :)
You need to set the destination viewcontroller property
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let destVc = segue.destinationViewController as? MinigameView else {
return
}
destVc.LightOrDark = self.LightDark
}}
This is wrong: self.LightOrDark = MinigameView.LightDark. Change it to:
MinigameView.LightDark = self.LightOrDark

Passing same object context 2 two separate view controllers

I have a managedObject that is being passed from 1 view controller to another the first pass works fine but when I try to pass the next object after the relationship has been set it doesn't send anything and comes back as either nil or if I try to use other methods comes back with a syntax error. The code I am using for the view controllers is as follows
View Controller 1, The first object set:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "popOver":
if let VC = segue.destinationViewController as? ClassDeckNameViewController
{
if let ppc = VC.popoverPresentationController {
VC.modalPresentationStyle = UIModalPresentationStyle.Popover
ppc.permittedArrowDirections = UIPopoverArrowDirection.Any
ppc.delegate = self
}
VC.classSave = (sender as! ClassSelection)
}
default: break
}
}
}
#IBAction func buttonPriest(sender: AnyObject) {
let entity = NSEntityDescription.entityForName("ClassSelection", inManagedObjectContext: classMOC!)
let newObject = ClassSelection(entity: entity!,insertIntoManagedObjectContext: classMOC)
newObject.classname = "Priest"
var error: NSError?
if let err = error {
println(err)
} else {
classMOC?.save(&error)
self.performSegueWithIdentifier("popOver", sender: newObject)
}
}
This passes the object without problem to the second view controller but this is the one that won't pass any further to the final presenting controller offering the user the final selections for their "Deck":
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showCardSelection" {
let detailVC: CardSelectionViewController = segue.destinationViewController as! CardSelectionViewController
detailVC.passedDeckObject = (sender as! Deck)
}
}
#IBAction func enterButton(sender: AnyObject) {
let entityDescription = NSEntityDescription.entityForName("Deck",inManagedObjectContext: managedObjectContext!)
let storeDeck = Deck(entity: entityDescription!,insertIntoManagedObjectContext: managedObjectContext)
storeDeck.deckname = usersDeckName.text
storeDeck.classSelected = classSave!
var error: NSError?
managedObjectContext?.save(&error)
if let err = error {
status.text = err.localizedFailureReason
} else {
usersDeckName.text = ""
status.text = "Deck Saved"
self.performSegueWithIdentifier("showCardSelection", sender: storeDeck)
}
}
I made passedDeckObject a variable of type Deck? in the final view controller to set the final relationship methods I know I am doing something wrong but I am unsure what! Any help with this would be amazing!
This looks to be a misconfiguration issue where the segue is being triggered directly in the storyboard rather than calling your code. As such the sender is a button rather than the new entity instance you're expecting.
To fix, disconnect the segue in the storyboard and connect (if it isn't already) the button to your action method in the view controller.

Swift Xcode 6 If Else statement check letters or numbers

I am trying to write and if else statement.
I need it to check if atextField is empty or has letters and if the textfield is empty or has letters is triggers a UIAlertWIndow.
I have tried boolean methods to no avail.
Any ideas?
This is what I have written so far:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if self.numOfGuestsData.text == "" {
alert()
println("Something Amish")
let alertController = UIAlertController(title: "Split The Bill", message:
"Please Enter The Number of Guests!", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default,handler: nil))
presentViewController(alertController, animated: true, completion: nil)
} else if self.numOfGuestsData.text != "" {
let subTotalVC = segue.destinationViewController as subTotalAmountViewController
subTotalVC.numOfGuests = numOfGuestsData.text
println("everything is Ok Here")
}
}
Also if I take out the alert window the if else statement fails for some reason.
Like if I write it like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if self.numOfGuestsData.text == "" {
alert()
println("Something Amish")
} else if self.numOfGuestsData.text != "" {
let subTotalVC = segue.destinationViewController as subTotalAmountViewController
subTotalVC.numOfGuests = numOfGuestsData.text
println("everything is Ok Here")
}
}
It just goes to the else...
Are you trying to suppress the segue if the textField is empty and present a UIAlertController instead if that is the case? Are you using a show segue? I think your logic needs to be moved out of prepareForSegue: and moved into shouldPerformSegueWithIdentifier:. Do your check in that method. Doing the logic in prepareForSegue: is too late; the segue is definitely going to happen by then.
Basically, you'll override shouldPerformSegueWithIdentifier: and then either return true or return false based on your logic. If it returns false, the segue won't happen.
Documentation here.

'bool' is not convertible to 'uint8'

I'm trying to build to-do app using Xcode 6 and Swift. I was able to run the app on Xcode 6 dp2 but after updating to dp7 I'm getting this error:
'bool' is not convertible to 'uint8'.
Here is the function with the error:
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
**if ((segue && segue!.identifier == "showdetails") != nil)**{
var selectedIndexPath:NSIndexPath = self.tableView.indexPathForSelectedRow()
var detailViewController:DetailViewController = segue!.destinationViewController as DetailViewController
detailViewController.toDoData = toDoItems.objectAtIndex(selectedIndexPath.row) as NSDictionary
}
}
The correct way to write that is:
if (segue != nil && segue!.identifier == "showdetails") {
but an even better way is using optional binding:
if let segue = segue {
if (segue.identifier == "showdetails") {
Note that there are other errors about incorrect usage of optionals. This is the modified code that compiles in playground:
if let segue = segue {
if (segue.identifier == "showdetails") {
var selectedIndexPath:NSIndexPath? = self.tableView.indexPathForSelectedRow()
if let selectedIndexPath = selectedIndexPath {
var detailViewController:DetailViewController = segue.destinationViewController as DetailViewController
detailViewController.toDoData = toDoItems.objectAtIndex(selectedIndexPath.row) as NSDictionary
}
}
}
indexPathForSelectedRow returns an optional, so you have to account for that.
Update: as pointed out by #MartinR, segue is no longer optional, so you can solve the problem by simply updating the function signature, and its implementation should look like:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "showdetails") {
var selectedIndexPath = self.tableView.indexPathForSelectedRow()
if let selectedIndexPath = selectedIndexPath {
var detailViewController = segue.destinationViewController as DetailViewController
detailViewController.toDoData = toDoItems.objectAtIndex(selectedIndexPath.row) as NSDictionary
}
}
}
First of all when I read the documentation what I read is :
func prepareForSegue(_ segue: UIStoryboardSegue, sender sender: AnyObject?)
UIKit seems to be updated in Beta7 to use less optionals. So segue may be not optional.
Then even if your function signature is good, you are comparing a Boolean to nil.
This (segue && segue!.identifier == "showdetails") is a boolean. A boolean is either true or false.
And at the very end, here is the best practice to unwrap a variable :
if let mySafeVariable = myOptionalVariable {
if mySafeVariable.attribute == <Whatever> {
}
}
You should. No, wait, you must read the Swift free iBooks.